首页 > 代码库 > SmartPointer_智能指针

SmartPointer_智能指针

动态内存

C++中程序用来存储动态分配(dynamically allocate)的对象——即那些在程序运行时分配的对象。

动态内存的生存期由程序控制,也就是当动态对象不再使用时,我们必须显示的销毁它们。

But众所周知(王小波句式),正确的管理动态内存是非常棘手的。如果忘了释放内存,就会导致内存泄漏;如果在还有指针引用内存时就去释放那块内存,那么那个指针就会变为一个引用非法内存的指针。thorny problem!

智能指针原理

So, 为了更容易更安全的使用动态内存,新的标准库提供了智能指针(smart pointer)类型来管理动态对象。

智能指针的行为类似常规指针,区别是它负责自动释放所指向的对象。

那么smart pointer是如何做到自动释放内存的呢?

其实,智能指针是一个类类型,假如给它起个类名叫SmartPtr吧。在这个SmartPtr类中,有一个private成员变量,这个变量是另外一种类类型的指针(就是说它是一个指针,指向一个类),然后通过这个指针来动态创建类的对象。

比如,这里创建了SmartPtr类和Animal类,SmartPtr中的成员变量ptr_为Animal类的一个指针。

代码如下:

#ifndef SMARTPTR#define SMARTPTR #include <iostream>//禁用赋值与复制#define DISALLOW_COPY_AND_ASSIGN(TypeName)     TypeName(const TypeName&);     void operator=(const TypeName&)class Animal{    public:        Animal()        {            std::cout << "construct......." << std::endl;        }        ~Animal()        {            std::cout << "destruct ... " << std::endl;        }        void run()        {            std::cout << "running......." << std::endl;        }};class SmartPtr{    public:        //SmartPtr针对的是heap上的对象        SmartPtr(Animal *ptr);        ~SmartPtr();        Animal &operator*();        const Animal &operator*() const;        Animal *operator->(); //重载SmartPtr这个类的->        const Animal *operator->() const;    private:        DISALLOW_COPY_AND_ASSIGN(SmartPtr);        Animal *ptr_; };#endif  /*SMARTPTR*/SmartPtr::SmartPtr(Animal *ptr)    :ptr_(ptr){}SmartPtr::~SmartPtr(){    delete ptr_; //SmartPtr析构时释放指向Animal类的指针,从而释放内存}Animal &SmartPtr::operator*(){    return *ptr_;}
//const 版本const Animal &SmartPtr::operator*() const{ return *ptr_;}Animal *SmartPtr::operator->(){ return ptr_;}//const版本const Animal *SmartPtr::operator->() const{ return ptr_;}

 然后我们编写一个异常处理函数来测试一下:

#include <stdexcept>#include "SmartPtr.hpp"using namespace std;int main(int argc, const char *argv[]){    try{        //这里的ptr离开try时一定会被销毁        //从而导致Animal对象一定会被析构        SmartPtr ptr(new Animal);        throw runtime_error("error");    }catch(runtime_error &e)    {        cout << e.what() << endl;		/*		construct...		destruct...		error		*/    }    return 0;}

这里补充一点:在异常处理函数中,如果在栈展开过程中退出了某个块(执行到throw语句),编译器将会负责确保在这个块中的对象能被正确的销毁。如果某个局部对象的类型是类类型,则该对象的析构函数将会被自动调用。

所以,上面程序中当执行到throw语句时,直接跳到catch中继续运行。那么原来try中的东东会确保被销毁,也就是编译器自动会去调用ptr这个对象的析构函数,从而执行了delete ptr_, 所以存储Animal对象的内存就被自动释放了。

一句话,智能指针利用了栈对象的生存期,将资源的获取放在构造函数里面,资源的释放放在析构函数里面,从而保证了资源一定会被正确释放。

最后,这也就是C++中的RAII(Resource Acquirement Is Initialization)

RAII要求,资源的有效期与持有资源的对象的生命期严格绑定,即由对象的构造函数完成资源的分配(获取),同时由析构函数完成资源的释放。在这种要求下,只要对象能正确地析构,就不会出现资源泄露问题。

SmartPointer_智能指针