再谈智能指针

http://www.cnblogs.com/lewiskyo/p/4214592.html  之前写过一篇文章介绍智能指针,并且简单实现了auto_ptr.

里面提到 auto_ptr 不能做为Stl容器的元素,原因具体是 http://www.360doc.com/content/14/0429/16/1317564_373230218.shtml

简要来说就是在对Stl容器元素进行复制构造时,不能改变原来的值(const T2& value),而auto_ptr在复制构造的时候,一定会修改元素的值(即将指向实际内存地址的指针置NULL),否则就会两个指针指向同一个地址,当析构的时候就会出现重复析构。

 

所以是赋值函数出了问题。

 

但如果仅使用构造函数,则是没问题的,如这里的例子 http://www.cnblogs.com/lewiskyo/p/4604839.html

 

而在引入shared_ptr后,这些问题都解决了,因为shared_ptr增加了引用数量这个变量。

 

这里想简单实现下 shared_ptr, 代码基于 http://www.cnblogs.com/yangshaoning/archive/2012/03/18/cpp_smart_pointer.html 

这里加上了模板,代码如下:

 

  1 #include <iostream>
  2 #include <vector>
  3 using namespace std;
  4 
  5 
  6 template <typename T> class SmartPtr;
  7 
  8 template<typename T>
  9 class RefPtr
 10 {
 11     friend class SmartPtr<T>;
 12 
 13     RefPtr(T *pointer = NULL):t( pointer), count(1)
 14     {
 15     }
 16 
 17     ~RefPtr()
 18     {
 19         cout << "destructor delete refptr" <<endl;
 20         delete t;
 21     }
 22 
 23     T *t;
 24     int count;
 25 
 26 };
 27 
 28 
 29 template<typename T>
 30 class SmartPtr
 31 {
 32     public:
 33 
 34         // 为了兼容stl预分配空间使用默认构造函数
 35         SmartPtr()
 36         {
 37             rp = NULL;
 38         }
 39 
 40         SmartPtr( T* object): rp(new RefPtr<T>(object))
 41         {
 42         }
 43 
 44         SmartPtr(const SmartPtr& rhs)
 45         {
 46             // 为了兼容stl预分配空间使用默认构造函数时,rp = NULL
 47             if ( rhs.rp != NULL)
 48             {
 49                 rp = rhs.rp;
 50                 ++rp->count;
 51             }
 52         }
 53 
 54         SmartPtr& operator=(const SmartPtr &rhs)
 55         {
 56             if(this == &rhs)
 57                 return *this;
 58             
 59             if (rp)
 60             {
 61                 --rp->count;
 62                 if (rp->count == 0)
 63                     delete rp;
 64             }
 65             
 66             
 67             rp = rhs.rp;
 68             ++rp->count;
 69     
 70             return *this;
 71         }
 72 
 73         ~SmartPtr()
 74         {
 75             if (rp)
 76             {
 77                 --rp->count;
 78                 if (rp->count == 0)
 79                     delete rp;                
 80             }
 81 
 82         }
 83 
 84     private:
 85         RefPtr<T> *rp;
 86 };
 87 
 88 
 89 int main()
 90 {
 91     
 92     {
 93         SmartPtr<int> s1(new int(10));
 94         SmartPtr<int> s2(s1);
 95     
 96         SmartPtr<int> s3 (new int (20));
 97         s3 = s1;
 98     }
 99 
100     cout << "operator v1" << endl;
101 
102     {
103         vector<SmartPtr<int> > v1;
104         v1.push_back(SmartPtr<int>(new int (10)));
105         v1.push_back(SmartPtr<int>(new int (10)));
106         v1.push_back(SmartPtr<int>(new int (10)));
107         v1.push_back(SmartPtr<int>(new int (10)));
108     }
109 
110     cout << "operator v1 end" << endl;
111 
112     cout << "operator v2" << endl;
113 
114     {
115         vector<SmartPtr<int> > v2(10);
116         v2[0] = SmartPtr<int>(new int (10));
117         v2[1] = SmartPtr<int>(new int (20));
118         v2[2] = SmartPtr<int>(new int (30));
119         v2[3] = SmartPtr<int>(new int (40));
120     }
121 
122     cout << "operator v2 end" << endl;
123 }

 

这里不管是Stl的构造函数,还是赋值函数都没问题了。

几个注意点:

1. 第六行需要前置声明SmartPtr,否则RefPtr会识别不了这个友元.

2. RefPtr::count仅在SmartPtr内改变值,所有指向同一个对象的SmartPtr操作同一个count。

3. SmartPtr::rp仅是一个指针,若然多个SmartPtr指向同一个对象,那么多个SmartPtr::rp则共享同一份地址,当SmartPtr析构时,--count,count==0时要 delete rp, 释放rp指向的地址,其他情况不必delete,只需要让系统回收rp指针所占用的地址即可。

 

后话:

  拿别人代码改造实现过程中有几个基础知识点值得在这里提一下的,也是提醒自己。

  1.  代码114行, vector<SmartPtr<int> >v2(10). 这里是常见的给vector预分配空间的做法,实际上是 调用10次 SmartPtr<int>() 默认构造函数得到10个实例放到容器里面。  代码116到119行, 执行SmartPtr的赋值函数,但此时 this->rp依然为NULL,所以不能执行 --count操作,要对指针是否为NULL进行判断。 当然这些操作都是为了能让智能指针加入Stl中作为元素使用而设定的。

  2.  vector.push_back(object). 实际上是调用类的复制构造函数。

posted @ 2017-01-01 16:56  逸马闪骑  阅读(305)  评论(0编辑  收藏  举报