开发文章

C++智能指针原理与实现

1.引入

复制内容到剪贴板
  1. int main()  
  2. {  
  3.     int *p = new int;   //裸指针  
  4.     delete p;  
  5.     return 0;  
  6. }  
 

在上面的代码中定义了一个裸指针p,需要我们手动释放。如果我们一不小心忘记释放这个指针或者在释放这个指针之前,发生一些异常,会造成严重的后果(内存泄露)。而智能指针也致力于解决这种问题,使程序员专注于指针的使用而把内存管理交给智能指针。
普通指针也容易出现指针悬挂问题,当有多个指针指向同一个对象的时候,如果某一个指针delete了这个对象,所以这个指针不会对这个对象进行操作,那么其他指向这个对象的指针呢?还在等待已经被删除的基础对象并随时准备对它进行操作。于是悬垂指针就形成了,程序崩溃也“指日可待”。

复制内容到剪贴板
  1. int main()  
  2. {  
  3.     int *p1 = new int(2);  
  4.     int *p2 = p1;  
  5.     int *p3 = p2;  
  6.     cout<<*p1<<endl;  
  7.     cout<<*p2<<endl;  
  8.     cout<<*p3<<endl;  
  9.     delete p1;  
  10.     cout<<*p2<<endl;  
  11.     return 0;  
  12. }  

输出结果

2 2 2 -572662307  输出的结果*p2的结果并不是期待中2,因为2早已经被删除了。 

 

早已经被删除了.png早已经被删除了.png

  1. 智能指针
    智能指针是一个类,它把普通指针封装起来,能实现和普通指针同样的功能。不同的是智能指针能够对内存进行自动管理,利用类对象出了作用域会调用析构函数,把对指针的释放写在析构函数中,避免出现悬挂指针的情况。
    智能指针(smart pointer)是存储指向动态分配(堆)对象指针的类,用于生存期控制,能够确保自动正确的销毁动态分配的对象,防止内存泄露。它的一种通用实现技术是使用引用计数(reference count)。智能指针类将一个计数器与类指向的对象相关联,引用计数跟踪该类有多少个对象共享同一指针。每次创建类的新对象时,初始化指针并将引用计数置为1;当对象作为另一对象的副本而创建时,拷贝构造函数拷贝指针并增加与之相应的引用计数;对一个对象进行赋值时,赋值操作符减少左操作数所指对象的引用计数(如果引用计数为减至0,则删除对象),并增加右操作数所指对象的引用计数;调用析构函数时,构造函数减少引用计数(如果引用计数减至0,则删除基础对象)。
    智能指针就是模拟指针动作的类。所有的智能指针都会重载 -> 和 * 操作符。智能指针还有许多其他功能,比较有用的是自动销毁。这主要是利用栈对象的有限作用域以及临时对象(有限作用域实现)析构函数释放内存。当然,智能指针还不止这些,还包括复制时可以修改源对象等。智能指针根据需求不同,设计也不同(写时复制,赋值即释放对象拥有权限、引用计数等,控制权转移等)。auto_ptr 即是一种常见的智能指针。
  2. 智能指针的实现(用类模板实现)
复制内容到剪贴板
  1. class Test  
  2. {  
  3. public:  
  4.     Test()  
  5.     {  
  6.         cout<<"Test()"<<endl;  
  7.     }  
  8.     ~Test()  
  9.     {  
  10.         cout<<"~Test()"<<endl;  
  11.     }  
  12.     void func()  
  13.     {  
  14.         cout<<"call Test::func()"<<endl;  
  15.     }  
  16. };  
  17. template<typename T>  
  18. class CSmartptr  
  19. {  
  20. public:  
  21.     CSmartptr(T *ptr):_ptr(ptr)  
  22.     {cout<<"CSmartptr()"<<endl;}  
  23.     CSmartptr(const CSmartptr<T> &other)  
  24.     {  
  25.         _ptr = new T;  
  26.         *ptr = *other._ptr;  
  27.     }  
  28.     ~CSmartptr()  
  29.     {  
  30.         cout<<"~CSmartptr()"<<endl;  
  31.         delete _ptr;  
  32.     }  
  33.     void relase() const  
  34.     {  
  35.         ((CSmartptr<T> *)this)->owns = false;  
  36.     }  
  37.     T& operator*()  
  38.     {  
  39.         return *_ptr;  
  40.     }  
  41.     const T& operator*()const {return *_ptr;}  
  42.     T *operator->()  
  43.     {  
  44.         return _ptr;  
  45.     }  
  46.     const T *operator->()const {return _ptr;}  
  47. private:  
  48.     T *_ptr;  
  49. };  
  50. int main()  
  51. {  
  52.     CSmartptr<int> p1(new int);  
  53.     *p1 = 200;  
  54.     CSmartptr<Test> p2(new Test);  
  55.     p2->func();  
  56.     return 0;  
  57. }  

1.模拟实现auto_ptr

复制内容到剪贴板
  1. template<typename T>  
  2. class CSmartptr  
  3. {  
  4. public:  
  5.     CSmartptr(T *ptr):_ptr(ptr),owns(true){cout<<"CSmartptr()"<<endl;}  
  6.     CSmartptr(const CSmartptr<T> &other)  
  7.     {  
  8.         other.relase();  
  9.         _ptr = other._ptr;  
  10.     }  
  11.     ~CSmartptr()  
  12.     {  
  13.         cout<<"~CSmartptr()"<<endl;  
  14.         if( owns == true)  
  15.         {  
  16.             cout<<"~CSmartptr()"<<endl;  
  17.             delete _ptr;  
  18.         }  
  19.   
  20.     }  
  21.     void relase() const  
  22.     {  
  23.         ((CSmartptr<T> *)this)->owns = false;  
  24.     }  
  25.     T& operator*()  
  26.     {  
  27.         return *_ptr;  
  28.     }  
  29.     const T& operator*()const {return *_ptr;}  
  30.     T *operator->()  
  31.     {  
  32.         return _ptr;  
  33.     }  
  34.     const T *operator->()const {return _ptr;}  
  35. private:  
  36.     T *_ptr;  
  37.     bool owns;  //标志位 ,控制一个资源的访问权限  
  38. };  
  39. int main()  
  40. {  
  41.     CSmartptr<int> p1(new int);  
  42.     *p1 = 200;  
  43.     CSmartptr<Test> p2(new Test);  
  44.     p2->func();  
  45.     return 0;  
  46. }  

带有引用计数的智能指针(方便对资源的管理和释放)

复制内容到剪贴板
  1. class CHeapTable  
  2. {  
  3. public:  
  4.     static CHeapTable& getInstance()  
  5.     {  
  6.         return mHeapTable;  
  7.     }  
  8.     //增加引用计数  
  9.     void addRef(void *ptr)  
  10.     {  
  11.         pthread_mutex_lock(mutex);  
  12.         list<Node>::iterator it = find(mList.begin(),  
  13.             mList.end(), ptr);  // Node == Node  it->mpaddr  
  14.         if(it == mList.end())  
  15.         {  
  16.             mList.push_front(ptr);  
  17.             cout<<"new addr:"<<ptr<<" ref:"<<1<<endl;  
  18.         }  
  19.         else  
  20.         {  
  21.             it->mcount++;  
  22.             cout<<"add addr:"<<ptr<<" ref:"<<it->mcount<<endl;  
  23.         }  
  24.         pthread_mutex_unlock(mutex);  
  25.     }  
  26.     //减少引用计数的  
  27.     void delRef(void *ptr)  
  28.     {  
  29.         list<Node>::iterator it = find(mList.begin(),  
  30.             mList.end(), ptr);  
  31.         if(it != mList.end())  
  32.         {  
  33.             it->mcount--;  
  34.             cout<<"del addr:"<<ptr<<" ref:"<<it->mcount<<endl;  
  35.             if(it->mcount == 0)  
  36.             {  
  37.                 mList.erase(it);  
  38.             }  
  39.         }  
  40.     }  
  41.     //获取引用计数的  
  42.     int getRef(void *ptr)  
  43.     {  
  44.         list<Node>::iterator it = find(mList.begin(),  
  45.             mList.end(), ptr);  
  46.         if(it != mList.end())  
  47.         {  
  48.             return it->mcount;  
  49.         }  
  50.         return 0;  
  51.     }  
  52. private:  
  53.     CHeapTable(){}  
  54.     static CHeapTable mHeapTable;  
  55.   
  56.     struct Node  
  57.     {  
  58.         Node(void *ptr=NULL):mpaddr(ptr),mcount(1){}  
  59.         bool operator==(const Node &src)  
  60.         {  
  61.             return mpaddr == src.mpaddr;  
  62.         }  
  63.         void *mpaddr; //标识堆内存资源  
  64.         int mcount; //标识资源的引用计数  
  65.     };  
  66.   
  67.     list<Node> mList;  
  68. };  
  69. CHeapTable CHeapTable::mHeapTable;  
  70. template<typename T>  
  71. class CSmartPtr  
  72. {  
  73. public:  
  74.     CSmartPtr(T *ptr = NULL)  
  75.         :mptr(ptr)  
  76.     {  
  77.         if(mptr != NULL)  
  78.         {  
  79.             addRef();  
  80.         }  
  81.     }  
  82.     ~CSmartPtr()  
  83.     {  
  84.         delRef();  
  85.         if(0 == getRef())  
  86.         {  
  87.             delete mptr;   
  88.             mptr = NULL;  
  89.         }  
  90.     }  
  91.   
  92.     CSmartPtr(const CSmartPtr<T> &src)  
  93.         :mptr(src.mptr)  
  94.     {  
  95.         if(mptr != NULL)  
  96.         {  
  97.             addRef();  
  98.         }  
  99.     }  
  100.   
  101.     CSmartPtr<T>& operator=(const CSmartPtr<T> &src)  
  102.     {  
  103.         if(this == &src)  
  104.             return *this;  
  105.   
  106.         delRef();  
  107.         if(0 == getRef())  
  108.         {  
  109.             delete mptr;  
  110.             mptr = NULL;  
  111.         }  
  112.   
  113.         mptr = src.mptr;  
  114.         if(mptr != NULL)  
  115.         {  
  116.             addRef();  
  117.         }  
  118.     }  
  119.     T& operator*(){return *mptr;}  
  120.     const T& operator*()const{return *mptr;}  
  121.     T* operator->(){return mptr;}  
  122.     const T* operator->()const{return mptr;}  
  123.   
  124.     void addRef(){mHeapTable.addRef(mptr);}  
  125.     void delRef(){mHeapTable.delRef(mptr);}  
  126.     int getRef(){return mHeapTable.getRef(mptr);}  
  127. private:  
  128.     T *mptr;  
  129.      static CHeapTable &mHeapTable;  
  130. };  
  131. template<typename T>  
  132. CHeapTable& CSmartPtr<T>::mHeapTable = CHeapTable::getInstance();  

 

感谢 Sweet_wen 支持 磐实编程网 原文地址:
blog.csdn.net/sweet_wen/article/details/76022274

文章信息

发布时间:2017-07-27

作者:Sweet_wen

发布者:aquwcw

浏览次数: