智能指针的引入
void func(int* ptr)
{
auto_ptr<int>p(new int);
if(ptr==NULL)
{
throw exception("ptr is null");//new 开辟了内存还没释放 抛出异常跳出了 就会产生内存泄露
//使用智能指针后 如果再对异常进行处理 就不会产生内存泄露
}
*p=*ptr;
//delete p;
}
int main()
{
func(NULL);
}
运用智能指针解决因程序异常退出,导致无法释放申请的堆内存或者其他原因导致的内存泄漏问题。
什么是智能指针
使用普通指针,容易造成堆内存泄露(忘记释放或其他原因),二次释放,释放了野指针程序崩溃等问题等,而使用智能指针能更好的管理堆内存。
C++11以前boost标准库只存在一种智能指针auto_ptr,但因存在较多的缺陷,在C++11以后摒弃了auto_ptr,并提出了另外三种智能指针:unique_ptr 、 shared_ptr 、weak_ptr。使用它们需要包含头文件 #include < memory>
首先智能指针并不是一个指针,智能指针是一个模板,由智能指针实例化出来的的对象具有和常规指针相似的行为,但是它能够自动的释放所指向的对象,所以我们称之为智能指针。
如果我们用普通指针来创建一个指向某个对象的指针,那么我们最后必须要手动释放这块空间,而智能指针它是一个类,它释放空间是通过析构函数完成的,正是由于有了这一层封装机制,所以智能指针才能够管理一个对象的生命周期。
定义一个类来封装资源的分配和释放,在构造函数完成资源的分配和初始化,在析构函数完成资源的清理,可以保证资源的正确初始化和释放。这样的方法称为RAII(Resource Acquisition is initialization)
对于编译器来说,智能指针实际上是一个栈对象,并非指针类型,在栈对象生命期即将结束时,智能指针通过析构函数释放由它管理的堆内存。
所以智能指针就是利用栈上的对象出作用域自动析构的特点,把资源释放的代码,放在智能指针的析构函数里面从而达到自动释放资源的目的
智能指针的设计原理和实现
自定义简单实现智能指针
// 自定义智能指针
template<typename T>
class CSmartPtr
{
public:
// 构造函数
CSmartPtr(T *ptr = nullptr)
:mptr(ptr) {}
~CSmartPtr() { delete mptr; }
private:
T *mptr;
};
int main()
{
CSmartPtr<int> ptr(new int);
return 0;
}
由于ptr是栈上的对象,不管是函数正常执行完,还是运行过程中出现异常,栈上的对象都会自动调用析构函数,在析构函数中进行了delete 操作,保证释放资源。
CSmartPtr<int> ptr(new int);
CSmartPtr<int> ptr1(ptr);
分析上述代码,由于我们未给智能指针提供拷贝构造函数,那么第二条语句则调用的是默认构造函数进行浅拷贝操作,我们注意到,ptr 与 ptr1 都持有相同的资源,那么程序结束,ptr1先调用析构函数释放了资源,当接下来ptr调用析构函数时,将会delete野指针,程序会出现严重的错误。
因此,智能指针就需要解决两个问题:
- 浅