引用计数的智能指针是对《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 请按任意键继续. . .