智能指针
1.为什么引入智能指针?
一个程序中可能因为各种情况导致内存泄漏问题,但是内存泄漏在一开始发生时并不是很容易被我们所发现,那我们先来看看内存泄漏的场景:
//1.执行流跳转导致没来得及释放
void test()
{
int *p = (int*)malloc(100);
//...
//...
return; //在遇到return , break, goto,continue等语句的时候,就会引发执行流跳转
free(p);
}
假如我们在程序开头部分new了一个变量或其他,那么与它配套使用的delete就应该出现在它的下一句,但是可能在他们两中间要有一些条件执行,这些条件中的某些语句可能引发程序结束或退出,那么后面的delete语句则不会被执行,也就是说我们前面申请的空间没有还给系统,这样就会导致内存的泄漏。
2.释放多次带来的安全问题
void func1()
{
//....
throw;
//....
}
void test()
{
int* p1 = (int*)malloc(100);
try
{
func();
}
catch(...)
{
delete p1;
throw;
}
delete p1;
}
2.智能指针的使用及原理
2.1RAII
RAII(Resource Acquisition Is Initialization -> 资源获得即初始化),是一种利用对象生命周期来控制程序资源的简单技术。在对象构造时获得资源,接着控制对资源的访问在对象的生命周期内始终有效,最后在对象析构时释放资源。这样的好处在于:
- 不需要显示的释放资源
- 对象所管理的资源在其生命周期内始终有效
2.2智能指针的原理
// 使用RAII思想设计的SmartPtr类
template<class T>
class SmartPtr {
public:
SmartPtr(T* ptr = nullptr)
: _ptr(ptr)
{}
T& operator*()//重载*模仿普通指针的行为
{
return *_ptr;
}
T* operator->()//如果我们的初始化了结构体指针,我们还需要用重载->来访问他的成员
{
return _ptr;
}
~SmartPtr()
{
if (_ptr)
delete _ptr;
}
private:
T* _ptr;
};
int main()
{
int* p = new int;
SmartPtr<int> sp(p);
*sp = 10;
cout << *sp << endl;
system("pause");
return 0;
}
总结一下智能指针的特性:
- RAII特性
- 重载operator*和opertaor->,具有像指针一样的行为。
3.C++中的智能指针
3.1智能指针的发展史
3.2auto_ptr
3.2.1auto_ptr的设计思路
成员函数有_ptr和_ower,构造函数时最开始就将对象的_owner赋为true,在拷贝构造或赋值操作后,将_owner改为false,这就实现了管理权的转移,使一块空间只能有一个管理员。析构时,只有_owner为true才有资格释放空间。这个做法会造成野指针的问题。下图会做解释。最好不要使用auto_ptr。
3.2.2auto_ptr模拟实现1.0
template<class T>
class AutoPtr
{
public:
AutoPtr(T* ptr = NULL)
:_ptr(ptr)
, _owner(true)
{}
AutoPtr(AutoPtr<T>& ap)
:_ptr(ap._ptr)
, _owner(ap._owner)
{
ap._owner = false;//ap的管理权到了this的手上,实现了管理权转移
}
AutoPtr<T>& operator&