cyendra

Azarath Metrion Zinthos

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

引用计数的智能指针是对《Effective C++ 条款13:以对象管理资源》的一个实现。

我们要设计一个智能指针,使他能够管理资源,在正确的实际调用资源的析构函数。

首先我们需要一个指针reference来指向资源,当智能指针构造时,用reference指针指向资源,在我们确定资源应该被析构时,我们对reference指针进行delete。

如果只有reference指针的话,只能实现出auto_ptr的效果,我们还需要添加引用计数系统counter来统计指向资源的智能指针的个数。counter不可以是一个普通的int型变量,因为不同的智能指针可能会有相同的计数,也不可以是一个static变量,因为同时存在的智能指针可以指向不同的资源,也就拥有不同的引用计数。因此将counter设计成一个指向int的指针,指向相同资源的智能指针的counter也指向相同的int值,这样对counter做修改时,就会影响到所有拥有这个counter的智能指针。

我们的智能指针还应该能实现多态的效果,因此指向同一个资源的智能指针中的reference指针可能有不同的类型。然而这就给我们的析构过程带来了困扰,我们在析构资源的时候需要知道资源原始的类型与指针,因此我们用一个指向void*的指针originalReference来保存原始的指针。

有了指向原始资源的指针,我们还需要原始资源的类型才能正常delete,我们在每个资源创建出来时,提供一个指向特殊的销毁函数的指针originalDestructor,保证这个函数能够成功的销毁资源。

有了这些成员变量我们就可以实现出一个简单的引用计数的智能指针。可见智能指针占用的空间要比普通指针大数倍。

按照《条款14:在资源管理类中小心copying行为》,仔细的为智能指针添加copying行为。

最后适当的重载操作符,使智能指针能够像一个普通指针那样使用。

 

  1 namespace cylib {
  2     
  3     // 引用计数操作器
  4     template<typename T> struct ReferenceCounterOperator
  5     {
  6         // 返回一个引用计数器
  7         static int* CreateCounter(T* reference)
  8         {
  9             return new int(0);
 10 
 11         }
 12         // 删除引用函数
 13         static void DeleteReference(int* counter, void* reference)
 14         {
 15             delete counter;// 删除计数器
 16             delete (T*)reference;// 删除资源
 17         }
 18     };
 19 
 20     
 21     // 智能指针类
 22     template<typename T> class SmartPtr
 23     {
 24     private:
 25         template<typename X> friend class SmartPtr;
 26         // 删除器
 27         typedef void (*Destructor)(int*, void*);
 28         // 引用计数器
 29         int* counter;
 30         // 引用资源,在拷贝过程中可能改变类型
 31         T* reference;
 32         // 原始引用资源,保持资源第一次创建时的指针
 33         void* originalReference;
 34         // 原始资源删除函数,在最后一个引用被析构时调用,删除资源
 35         Destructor originalDestructor;
 36 
 37         // 增加引用计数
 38         void Inc()
 39         {
 40             if (counter)
 41             {
 42                 ++(*counter);
 43             }
 44         }
 45         // 减少引用计数,如果资源不再被引用则删除资源
 46         void Dec()
 47         {
 48             if (counter)
 49             {
 50                 if (--(*counter) == 0)
 51                 {
 52                     originalDestructor(counter, originalReference);
 53                     counter = 0;
 54                     reference = 0;
 55                     originalReference = 0;
 56                     originalDestructor = 0;
 57                 }
 58             }
 59         }
 60 
 61         // 返回当前计数器
 62         int* Counter() const
 63         {
 64             return counter;
 65         }
 66 
 67         // 私有构造器
 68         SmartPtr(int* _counter, T* _reference, void* _originalReference, Destructor _originalDestructor)
 69             : counter(_counter)
 70             , reference(_reference)
 71             , originalReference(_originalReference)
 72             , originalDestructor(_originalDestructor)
 73         {
 74             Inc();
 75         }
 76 
 77     public:
 78         // 获取资源的直接指针
 79         T* get() const
 80         {
 81             return reference;
 82         }
 83         // 重载->操作符
 84         T* operator->()const
 85         {
 86             return reference;
 87         }
 88         // 重载*操作符,危险!
 89         T& operator*() const {
 90             return *reference;
 91         }
 92 
 93         // 构造一个空的智能指针,不指向任何资源
 94         SmartPtr()
 95             : counter(0)
 96             , reference(0)
 97             , originalReference(0)
 98             , originalDestructor(0)
 99         {}
100         // 用一个普通指针构造智能指针,是最基本的用法
101         SmartPtr(T* pointer)
102             : counter(0)
103             , reference(0)
104             , originalReference(0)
105             , originalDestructor(0)
106         {
107             if (pointer)
108             {
109                 counter = ReferenceCounterOperator<T>::CreateCounter(pointer);// 创建新的计数器
110                 reference = pointer;// 获取当前资源的引用
111                 originalReference = pointer;// 将原始资源置为当前资源
112                 originalDestructor = ReferenceCounterOperator<T>::DeleteReference;// 连接删除器
113                 Inc();// 引用计数增加
114             }
115         };
116         // 用另一个同类型的智能指针进行拷贝构造,不创建新资源
117         SmartPtr(const SmartPtr<T>& pointer)
118             : counter(pointer.counter)
119             , reference(pointer.reference)
120             , originalReference(pointer.originalReference)
121             , originalDestructor(pointer.originalDestructor)
122         {
123             Inc();// 引用计数增加
124         }
125         // 用其他类型的智能指针进行转型拷贝构造,不创建新资源
126         // 将原始类型U转换为当前智能指针的类型T,但是原始资源与原始删除器不变
127         template<typename U> SmartPtr(const SmartPtr<U>& pointer)
128             : counter(0)
129             , reference(0)
130             , originalReference(0)
131             , originalDestructor(0)
132         {
133             T* converted = pointer.get();
134             if (converted)
135             {
136                 counter = pointer.Counter();
137                 reference = converted;
138                 originalReference = pointer.originalReference;
139                 originalDestructor = pointer.originalDestructor;
140                 Inc();
141             }
142         }
143 
144         // 析构当前的智能指针,减少引用计数
145         ~SmartPtr()
146         {
147             Dec();
148         }
149 
150         // 将一个普通指针的值赋给智能指针
151         // 智能指针之前引用的资源取消,由普通指针构造出新的智能指针
152         // 构造失败则将智能指针置为空
153         SmartPtr<T>& operator=(T* pointer)
154         {
155             Dec();// 原本的资源引用减少
156             if (pointer)
157             {
158                 counter = ReferenceCounterOperator<T>::CreateCounter(pointer);
159                 reference = pointer;
160                 originalReference = pointer;
161                 originalDestructor = &ReferenceCounterOperator<T>::DeleteReference;
162                 Inc();
163             }
164             else
165             {
166                 counter = 0;
167                 reference = 0;
168                 originalReference = 0;
169                 originalDestructor = 0;
170             }
171             return *this;
172         }
173         // 将另一个智能指针的值赋给自身
174         // 智能指针之前引用的资源取消,并引用新的智能指针的资源
175         SmartPtr<T>& operator=(const SmartPtr<T>& pointer)
176         {
177             if (this != &pointer)// 判断是否自赋值
178             {
179                 Dec();
180                 counter = pointer.counter;
181                 reference = pointer.reference;
182                 originalReference = pointer.originalReference;
183                 originalDestructor = pointer.originalDestructor;
184                 Inc();
185             }
186             return *this;
187         }
188         // 将一个不同类型的智能指针赋给自身
189         // 智能指针之前引用的资源取消,并引用新的智能指针的资源
190         // 转型失败的话返回空智能指针
191         template<typename U> SmartPtr<T>& operator=(const SmartPtr<U>& pointer)
192         {
193             T* converted = pointer.get();
194             Dec();
195             if (converted)
196             {
197                 counter = pointer.counter;
198                 reference = converted;
199                 originalReference = pointer.originalReference;
200                 originalDestructor = pointer.originalDestructor;
201                 Inc();
202             }
203             else
204             {
205                 counter = 0;
206                 reference = 0;
207                 originalReference = 0;
208                 originalDestructor = 0;
209             }
210             return *this;
211         }
212 
213         // 重载比较操作符,用于比较智能指针与普通指针是否指向相同资源
214         bool operator==(const T* pointer)const { return reference == pointer; }
215         bool operator!=(const T* pointer)const { return reference != pointer; }
216         bool operator>(const T* pointer)const { return reference>pointer; }
217         bool operator>=(const T* pointer)const { return reference >= pointer; }
218         bool operator<(const T* pointer)const { return reference<pointer; }
219         bool operator<=(const T* pointer)const { return reference <= pointer; }
220 
221         // 重载比较操作符,用于比较两个智能指针是否指向相同资源
222         bool operator==(const SmartPtr<T>& pointer)const { return reference == pointer.reference; }
223         bool operator!=(const SmartPtr<T>& pointer)const { return reference != pointer.reference; }
224         bool operator>(const SmartPtr<T>& pointer)const { return reference>pointer.reference; }
225         bool operator>=(const SmartPtr<T>& pointer)const { return reference >= pointer.reference; }
226         bool operator<(const SmartPtr<T>& pointer)const { return reference<pointer.reference; }
227         bool operator<=(const SmartPtr<T>& pointer)const { return reference <= pointer.reference; }
228 
229         // 智能指针指向非空时有true的布尔值
230         operator bool()const{ return reference != 0; }
231 
232     };
233     
234 }

 

测试代码:

 1 #include <iostream>
 2 #include "SmartPoint.h"
 3 using namespace std;
 4 
 5 class B {
 6 public:
 7     B() { cout << "构造了一个基类~" << endl; }
 8     virtual ~B() { cout << "基类被析构啦!" << endl; }
 9     virtual void message() { cout << "基基基基基基基基基基基基" << endl; }
10 };
11 
12 class D : public B {
13 public:
14     D() { cout << "构造了一个派生类~" << endl; }
15     virtual ~D() { cout << "派生类被析构啦!" << endl; }
16     virtual void message() { cout << "派派派派派派派派派派派派" << endl; }
17 };
18 
19 void test1() { 
20     cout << "构造演示:" << endl;
21     cylib::SmartPtr<B> bp = new B();
22     cylib::SmartPtr<B> bp2(new B());
23 }
24 void test2() { 
25     cout << "比较演示:" << endl;
26     cylib::SmartPtr<B> bp = new B();
27     B* p = bp.get();
28     cylib::SmartPtr<B> bp2 = bp;
29     if (bp == p) cout << "相等" << endl;
30     if (bp == bp2) cout << "相等" << endl;
31 }
32 void test3() {
33     cout << "多态演示:" << endl;
34     cylib::SmartPtr<B> bp;
35     cylib::SmartPtr<D> dp = new D();
36     bp = dp;
37     bp->message();
38 }
39 
40 
41 int main()
42 {
43     cout << "---------------" << endl;
44     test1();
45     cout << "---------------" << endl;
46     test2();
47     cout << "---------------" << endl;
48     test3();
49     cout << "---------------" << endl;
50     system("pause");
51 
52 }

 

测试结果:

 1 ---------------
 2 构造演示:
 3 构造了一个基类~
 4 构造了一个基类~
 5 基类被析构啦!
 6 基类被析构啦!
 7 ---------------
 8 比较演示:
 9 构造了一个基类~
10 相等
11 相等
12 基类被析构啦!
13 ---------------
14 多态演示:
15 构造了一个基类~
16 构造了一个派生类~
17 派派派派派派派派派派派派
18 派生类被析构啦!
19 基类被析构啦!
20 ---------------
21 请按任意键继续. . .

 

posted on 2014-09-01 19:34  cyendra  阅读(867)  评论(0编辑  收藏  举报