智能指针及其解析

1.智能指针:智能指针就是智能的、自动化的管理指针所指向的动态资源的释放,并且可以如同指针一样使用。智能指针是RALL(初始化立即获取资源)思想的一种实现,其中初始化利用构造函数,之后将资源保存起来最后让析构函数自动清理。 

2.引入智能指针原因:总的来说,是防止程序执行流的改变、或者人为因素造成的内存泄露问题,在此我们应该知道,影响执行流改变的常见语句有:goto,抛异常,return,break,continue等。

3.智能指针发展:
(1)最早期的auto_ptr
autoptr是一种有着严重缺陷的智能指针,缺陷在于当我们进行拷贝构造时,如果为浅拷贝时,可能会出现同一块空间释放多次的问题,如果为深拷贝也不合理,因为
指针的拷贝,本身就希望指向同一块空间;因此,在拷贝构造这里就出现了大的问题。

关于auto_ptr的模拟实现:

  1. template <class T>  
  2. class AutoPtr  
  3. {  
  4. private:  
  5.     T* _ptr;  
  6. public:  
  7.     AutoPtr(T* ptr)//构造函数  
  8.         :_ptr(ptr)  
  9.     {}  
  10.   
  11.   
  12.     ~AutoPtr()//析构函数  
  13.     {  
  14.         cout<<"~AutoPtr()//析构函数"<<endl;  
  15.         if(_ptr)  
  16.         {  
  17.             delete _ptr;  
  18.         }  
  19.     }  
  20.   
  21.     //1.管理权的转移  
  22.     //问题缺陷:当一个智能指针交出对空间的管理权之后,将它置空,不能再对其解引用赋值,废掉  
  23.     AutoPtr(AutoPtr<T>& ap)//拷贝构造函数  
  24.     {  
  25.         _ptr=ap._ptr;  
  26.         ap._ptr=NULL;//退出管理  
  27.     }  
  28.   
  29.     AutoPtr<T>& operator=(AutoPtr<T>& ap)//赋值操作符的重载  
  30.     {  
  31.         if(this!=&ap)  
  32.         {  
  33.             if(_ptr)  
  34.             {  
  35.                 delete _ptr;  
  36.             }  
  37.             _ptr=ap._ptr;  
  38.             ap._ptr=NULL;//退出管理  
  39.         }  
  40.         return *this;  
  41.     }  
  42.   
  43.     T& operator*()//重载*  
  44.     {  
  45.         return *_ptr;  
  46.     }  
  47.   
  48.     T* operator->()//重载->  
  49.     {  
  50.         return _ptr;  
  51.     }  
  52.   
  53. };  
解决方案:管理权转移
即再解决对象赋值、拷贝构造的时候,如a=b,先将a的地址空间释放,然后将b.ptr指针赋值给a.ptr,最后将地址空间的管理权交给a.ptr,并且将 b.ptr置为NULL.所以,在此操作
之后,原来的指针将不能再使用,因此其缺点在于,一个智能指针只能指向一块内存,不能有几个指针指向同一块内存空间。

鉴于autoptr的严重缺陷,开发者又自主实现解决以上弊端的智能指针:
(2)scoped_ptr
它所采用的解决方案就是防函数,对拷贝构造函数、赋值运算符的重载声明为私有的 或者保护的,但不去实现它,即实现了防止拷贝,防止赋值的功能

关于scoped_ptr的模拟实现:

  1. template <class T>  
  2. class ScopedPtr  
  3. {  
  4. protected:  
  5.     T* _ptr;  
  6. public:  
  7.     ScopedPtr(T* ptr)//构造函数  
  8.         :_ptr(ptr)  
  9.     {}  
  10.   
  11.     ~ScopedPtr()//析构函数  
  12.     {  
  13.         if(_ptr)  
  14.         {  
  15.             delete _ptr;  
  16.         }  
  17.     }  
  18.   
  19.     T& operator*()//*的重载  
  20.     {  
  21.         return *_ptr;  
  22.     }  
  23.   
  24.     T* operator->()//重载->  
  25.     {  
  26.         return _ptr;  
  27.     }  
  28.   
  29.     //防拷贝的实现,即将拷贝构造、赋值运算符重载函数声明成私有的,并且不定义  
  30. private:  
  31.     ScopedPtr(const ScopedPtr<T>& sp);  
  32.     ScopedPtr<T>& operator=(const ScopedPtr<T>& sp);  
  33. };  
虽然 表面上解决了auto_ptr的缺陷,但是没有了拷贝、赋值功能,为了不仅可以 屏蔽auot_ptr缺陷,还能拷贝、赋值,我们又提出来了一下:
(3)shared_ptr

它所采用的技术是引用计数思想,在对象构造时记下使用次数,到最后只有一个引用计数的时候再释放,所以依然支持拷贝构造和赋值的操作

关于shared_ptr的模拟实现:

  1. template <class T>  
  2. class SharedPtr  
  3. {  
  4. protected:  
  5.     T* _ptr;  
  6.     int* _RefCount;  
  7. public:  
  8.     SharedPtr(T* ptr)//构造函数  
  9.         :_ptr(ptr)  
  10.         ,_RefCount(new int(1))  
  11.     {}  
  12.   
  13.     ~SharedPtr()//析构函数  
  14.     {  
  15.         if(--(*_RefCount)==0)  
  16.         {  
  17.             delete _ptr;  
  18.             delete _RefCount;  
  19.         }  
  20.     }  
  21.   
  22.     SharedPtr(SharedPtr<T>& sp)//拷贝构造函数  
  23.     {  
  24.         _ptr=sp._ptr;  
  25.         _RefCount=sp._RefCount;  
  26.         ++(*_RefCount);//拷贝构造之后,this多了一个对象指向自己的空间  
  27.     }  
  28.   
  29.     SharedPtr<T>& operator=(SharedPtr<T>& sp)//赋值运算符的重载  
  30.     {  
  31.         if(_ptr!=sp._ptr)  
  32.         {  
  33.             if(--(*_RefCount)==0)  
  34.             {  
  35.                 delete _ptr;//转变指向之前,先检查自己原来在的那块空间是否只有自己一个人管理  
  36.                 delete_RefCount;  
  37.             }  
  38.             _ptr=sp._ptr;  
  39.             ++(*_RefCount);  
  40.         }  
  41.         return *this;  
  42.     }  
  43.   
  44.     T& operator*()//*的重载  
  45.     {  
  46.         return *_ptr;  
  47.     }  
  48.   
  49.     T* operator->()//重载->  
  50.     {  
  51.         return _ptr;  
  52.     }  
  53.   
  54. };  
shared_ptr可以说是比较完美的智能指针了,解决了它之前几个智能指针所存在的问题但是,它的缺陷却在于,它存在着循环引用的问题:

关于循环引用:在使用shared_ptr时,由于节点之间的相互引用使得多个结点指向同一块空间,引用计数不为1,从而在释放空间时,p1等p2释放,p2等p1释放,从而引起的循环引用问题,造成内存泄露。


此时又提出来了以下指针:
(4)weak_ptr
weak_ptr是为了配合shared_ptr而引入的一种智能指针,它更像是shared_ptr的一个助手而不是智能指针,因为它不具有普通指针的行为,像旁观者那样观测资源的使用情况但weak_ptr没有共享资源,它的构造不会引起指针引用计数的增加。

引入weak_ptr弱引用指针即可解决循环引用问题。weak_ptr不会修改引用计数。

关于weak_pt的模拟实现:

  1. template<class T>  
  2. class WeakPtr  
  3. {  
  4.     WeakPtr()  
  5.         :_ptr(NULL)  
  6.     {}  
  7.   
  8.     WeakPtr(const SharedPtr<T>& sp)  
  9.         :_ptr(sp._ptr)  
  10.     {}  
  11.   
  12.     T& operator*()//*的重载  
  13.     {  
  14.         return *_ptr;  
  15.     }  
  16.   
  17.     T* operator->()//重载->  
  18.     {  
  19.         return _ptr;  
  20.     }  
  21. private:  
  22.     T* _ptr;  
  23.   
  24. }; 
全部评论

相关推荐

点赞 评论 收藏
分享
评论
点赞
1
分享
牛客网
牛客企业服务