Published by orzz.org(). (https://orzz.org/%e6%94%af%e6%8c%81%e5%bc%95%e7%94%a8%e8%ae%a1%e6%95%b0%e7%9a%84%e6%99%ba%e8%83%bd%e6%8c%87%e9%92%88%e7%b1%bb%e6%a8%a1%e6%9d%bf/)
智能指针是很多人喜欢思考的一种内存管理方案...虽然这种方案本身存在一些硬伤,但是在很多需要自动化处理,且使用方式相对较简单的场合里应用还是比较多的.
先发一个我最初写好的版本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 |
////////////////////////////////////////////////////////////////// // TSmartPtr - 智能指针类模板 // // Author: 木头云 // Blog: http://darkc.at // E-Mail: memleak@darkc.at // Version: 1.0.819.1654(2009/08/19) // // History: // - 1.0.813.1148(2009/08/13) @ 完成基本的类模板构建 // - 1.0.814.1758(2009/08/14) + 添加TSmartPtr类相关操作符重载(==) // + 添加CSmartPtrManager智能指针管理类及全局的智能指针管理链表 // - 1.0.817.1508(2009/08/17) ^ 优化CSmartPtrManager使之支持引用计数 // + 添加TSmartPtr类相关操作符重载(*) // - 1.0.818.1600(2009/08/18) ^ 优化CSmartPtrManager指针管理链表的list为map // - 删除CSmartPtrManager类的Find()函数 // = 调整TSmartPtr类模板参数,将is_ary改为DelFunction函数指针 // = 调整CSmartPtrManager类,将其函数改为静态函数,并定义自动回收对象CAutoRecycle // + 添加CDelFunc类,用于统一管理指针删除算法 // - 1.0.819.1654(2009/08/19) + TSmartPtr类添加相关操作符重载([],+,-) // # 修正当指针自我复制时导致的指针被销毁的bug ////////////////////////////////////////////////////////////////// #pragma once #include <map> using namespace std; ////////////////////////////////////////////////////////////////// // 指针类型重定义 typedef void* _Ptr; // 指针销毁函数指针重定义 typedef void (*_DelFun)(_Ptr p); ////////////////////////////////////////////////////////////////// // CDelFunc - 指针删除算法类 class CDelFunc { public: inline static void DelSingle(_Ptr p) { if(p) delete p; } inline static void DelArray(_Ptr p) { if(p) delete [] p; } }; // CDelFunc - 指针删除算法类 结束 ////////////////////////////////////////////////////////////////// // CSmartPtrManager - 智能指针管理类 class CSmartPtrManager { // 内部数据结构 protected: // 内部指针结构 struct _PTR { _Ptr p_ptr; _DelFun p_fun; unsigned int u_ref; _PTR() : p_ptr(NULL) , p_fun(NULL) , u_ref(0) { } _PTR(const _PTR& _ptr) : p_ptr(_ptr.p_ptr) , p_fun(_ptr.p_fun) , u_ref(_ptr.u_ref) { } void operator=(const _PTR& _ptr) { this->p_ptr = _ptr.p_ptr; this->p_fun = _ptr.p_fun; this->u_ref = _ptr.u_ref; } operator _Ptr() { return this->p_ptr; } void DelPtr() { (*(this->p_fun))(this->p_ptr); } }; // 内部指针结构 结束 // 自动回收对象 class CAutoRecycle { public: ~CAutoRecycle() { /* 当程序退出时可以自动回收 所有仍未被回收的指针 */ CSmartPtrManager::ClrRef(); } }; // 自动链表对象 结束 // 友元 private: friend CAutoRecycle; // 成员变量 protected: static map<_Ptr, _PTR> lst_ptr; static CAutoRecycle auto_rec; // 操作 public: static void AddRef(_Ptr ptr, _DelFun _del_fun) { map<_Ptr, _PTR>::iterator iter = lst_ptr.find(ptr); if( iter != lst_ptr.end() ) { iter->second.u_ref ++ ; return ; } _PTR _ptr; _ptr.p_ptr = ptr; _ptr.p_fun = _del_fun; _ptr.u_ref = 1; lst_ptr.insert( map<_Ptr, _PTR>::value_type(ptr, _ptr) ); } static void DelRef(_Ptr ptr) { map<_Ptr, _PTR>::iterator iter = lst_ptr.find(ptr); if( iter != lst_ptr.end() ) { if( iter->second ) { if( -- iter->second.u_ref ) return ; iter->second.DelPtr(); // 删除指针 lst_ptr.erase( iter ); return ; } } } protected: static void ClrRef() { // 回收所有指针 map<_Ptr, _PTR>::iterator iter = lst_ptr.begin(); while( iter != lst_ptr.end() ) { _PTR _ptr( iter++->second ); if( !_ptr.u_ref ) continue ; _ptr.DelPtr(); // 删除指针 } lst_ptr.clear(); } }; // CSmartPtrManager - 智能指针管理类 结束 ////////////////////////////////// // 初始化静态变量 map<_Ptr, CSmartPtrManager::_PTR> CSmartPtrManager::lst_ptr; CSmartPtrManager::CAutoRecycle CSmartPtrManager::auto_rec; ////////////////////////////////////////////////////////////////// // TSmartPtr - 智能指针类模板 template<class TYPE, _DelFun DelFunction = CDelFunc::DelSingle> class TSmartPtr { // 成员变量 protected: TYPE* m_ptr; // 构造/析构 public: TSmartPtr(void) { m_ptr = NULL; } TSmartPtr(TYPE* pt) { (*this) = pt; } TSmartPtr(const TSmartPtr& ptr) { (*this) = ptr; } virtual ~TSmartPtr(void) { Release(); } // 操作 public: void Release() { if( m_ptr ) { CSmartPtrManager::DelRef(m_ptr); m_ptr = NULL; } } ////////////////////////////////// void operator=(TYPE* pt) { if( (*this) == pt ) return ; Release(); m_ptr = pt; CSmartPtrManager::AddRef(m_ptr, DelFunction); } void operator=(const TSmartPtr& ptr) { if( (*this) == ptr ) return ; Release(); this->m_ptr = ptr.m_ptr; CSmartPtrManager::AddRef(m_ptr, DelFunction); } bool operator==(TYPE* pt) const { return (m_ptr == pt); } bool operator==(const TSmartPtr& ptr) const { return (this->m_ptr == ptr.m_ptr); } TYPE* operator+(int offset) const { return (m_ptr + offset); } TYPE* operator-(int offset) const { return (m_ptr - offset); } TYPE* operator->() const { return m_ptr; } TYPE& operator*() { return *m_ptr; } TYPE& operator[](int inx) { return m_ptr[inx]; } operator TYPE*() const { return m_ptr; } }; // TSmartPtr - 智能指针类模板 结束 |
使用示例:
1 2 3 4 5 6 7 8 |
TSmartPtr<int> pi = new int; (*pi) = 2; TSmartPtr<int> pi2 = pi; cout << (*pi) << " " << (*pi2) << endl; // ... TSmartPtr<ClassA> pc = new ClassA; pc->FuncA(); // ... |
以上的智能指针类解决了包括指针多次复制导致的析构删除错误等问题,利用一个静态的管理类纪录了所有当前存在的指针,每次添加新指针时就在静态指针map中登记,若当前指针已存在就将对应的引用计数加1...
不过使用这种方法管理引用计数有一个很大的缺点,就是每次添加或删除指针时必须要查找指针map,效率上会有所损失.但是这样做的好处是不会因为将普通指针赋值给智能指针而导致引用计数的管理混乱.
通常智能指针的解决方案是封装一个用于计数的指针封装类,在智能指针类创建新智能指针时new一个新的计数类并保存它的指针,当出现智能指针之间的拷贝时通过自己保存的计数类指针对计数进行操作,等同于操作了所有拥有这个计数类指针的智能指针的引用计数.这样做就不需要任何查表的操作了,但是不好的地方是一个指针引用计数类的实例并没有严格的与一个指针相绑定...但是只要严格注意使用规范(比如不要使用普通指针直接构造智能指针,在构造新智能指针时一定要使用new出来的新指针),是不会出现指针计数管理出现混乱的错误的.
在实际使用中,我还发现上面的代码还有因指针型别不同导致指针转换不方便,以及当使用类指针时此智能指针析构函数不会调用其析构函数等一些问题.
下面是一个改进版的TSmartPtr:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 |
////////////////////////////////////////////////////////////////// // TSmartPtr - 智能指针类模板 // // Author: 木头云 // Blog: http://darkc.at // E-Mail: memleak@darkc.at // Version: 1.1.831.1200(2009/08/31) // // History: // - 1.0.813.1148(2009/08/13) @ 完成基本的类模板构建 // - 1.0.814.1758(2009/08/14) + 添加TSmartPtr类相关操作符重载(==) // + 添加CSmartPtrManager智能指针管理类及全局的智能指针管理链表 // - 1.0.817.1508(2009/08/17) ^ 优化CSmartPtrManager使之支持引用计数 // + 添加TSmartPtr类相关操作符重载(*) // - 1.0.818.1600(2009/08/18) ^ 优化CSmartPtrManager指针管理链表的list为map // - 删除CSmartPtrManager类的Find()函数 // = 调整TSmartPtr类模板参数,将is_ary改为DelFunction函数指针 // = 调整CSmartPtrManager类,将其函数改为静态函数,并定义自动回收对象CAutoRecycle // + 添加CDelFunc类,用于统一管理指针删除算法 // - 1.0.819.1720(2009/08/19) + 添加TSmartPtr类相关操作符重载([],+,-) // = 调整TSmartPtr类=操作符的返回值为TSmartPtr& // # 修正当指针自我复制时导致的指针被销毁的bug // - 1.1.820.2300(2009/08/20) + 添加TSmartPtr类相关成员函数对不同型别指针的支持 // - 删除CSmartPtrManager管理类,让TSmartPtr类使用TPtr指针计数类指针自动管理指针计数 // = 调整_Ptr及_DelFun类型重定义到CDelFunc类内部 // ^ 优化TSmartPtr(TYPE*)构造函数的执行效率 // = 调整类及其成员函数的声明格式 // - 1.1.821.1645(2009/08/21) + 添加TPtr类相关操作符重载(!=) // + 添加TSmartPtr类相关操作符重载(!=) // - 1.1.825.1255(2009/08/25) # 修正TSmartPtr类bool operator==()与bool operator!=()对NULL指针的判断错误 // - 1.1.827.1353(2009/08/27) = 调整TPtr与TSmartPtr类模板TYPE参数的默认值为CDelFunc::_Ptr // - 1.1.831.1200(2009/08/31) # 修正当使用类指针,智能指针析构时不会调用其析构函数的bug ////////////////////////////////////////////////////////////////// #ifndef __STDCPX_SMARTPTR_H__ #define __STDCPX_SMARTPTR_H__ #pragma once ////////////////////////////////////////////////////////////////// // 指针类型重定义 typedef void* _Ptr; ////////////////////////////////////////////////////////////////// // TPtr - 指针计数类 声明 template<class TYPE = _Ptr, bool ARRAY = false> class TPtr; // TSmartPtr - 智能指针类模板 声明 template<class TYPE = _Ptr, bool ARRAY = false> class TSmartPtr; ////////////////////////////////////////////////////////////////// // 指针计数类 template<class TYPE, bool ARRAY> class TPtr { // 友元 protected: friend class TSmartPtr<TYPE, ARRAY>; // 成员变量 protected: TYPE* p_ptr; unsigned int u_ref; // 构造/析构 protected: TPtr() : p_ptr(NULL) , u_ref(0) { } explicit TPtr(TYPE* pt) : p_ptr(pt) , u_ref(1) { } virtual ~TPtr() { // 调用合适的清理函数 if( ARRAY ) delete [] p_ptr; else delete p_ptr; } // 操作 protected: unsigned int GetRefCount() { return u_ref; } TYPE* GetPtr() { return p_ptr; } ////////////////////////////////// bool operator==(TYPE* pt) const { return (p_ptr == pt); } bool operator!=(TYPE* pt) const { return (p_ptr != pt); } void operator++() { ++ u_ref; } void operator--() { if( -- u_ref ) { return ; } delete this; } TYPE& operator*() { return *p_ptr; } operator TYPE*() { return p_ptr; } }; // 指针计数类 结束 ////////////////////////////////////////////////////////////////// // TSmartPtr - 智能指针类模板 template<class TYPE, bool ARRAY> class TSmartPtr { // 友元 protected: template<class TYPE2, bool ARRAY> friend class TSmartPtr; // 成员变量 protected: TPtr<TYPE, ARRAY>* m_ptr; // 构造/析构 public: TSmartPtr(void) : m_ptr(NULL) { } TSmartPtr(TYPE* pt) : m_ptr(NULL) { if( !pt ) return ; m_ptr = new TPtr<TYPE, ARRAY>(pt); } TSmartPtr(const TSmartPtr<TYPE>& ptr) : m_ptr(NULL) { (*this) = ptr; } ////////////////////////////////// template<class TYPE2> TSmartPtr(TYPE2* pt) : m_ptr(NULL) { if( !pt ) return ; m_ptr = new TPtr<TYPE, ARRAY>((TYPE*)pt); } template<class TYPE2> TSmartPtr(const TSmartPtr<TYPE2>& ptr) : m_ptr(NULL) { (*this) = ptr; } ////////////////////////////////// virtual ~TSmartPtr(void) { if( m_ptr ) -- (*m_ptr); } // 操作 public: unsigned int GetRefCount() { if( m_ptr ) return m_ptr->GetRefCount(); else return 0; } void Release() { if( m_ptr ) delete m_ptr; m_ptr = NULL; } ////////////////////////////////// TSmartPtr<TYPE, ARRAY>& operator=(const TSmartPtr<TYPE, ARRAY>& ptr) { if( (*this) == ptr ) return (*this); if( m_ptr ) -- (*m_ptr); m_ptr = ptr.m_ptr; if( m_ptr ) ++ (*m_ptr); return (*this); } bool operator==(TYPE* pt) const { if( m_ptr ) return ((*m_ptr) == (TYPE*)pt); else if( !pt ) return true; else return false; } bool operator==(const TSmartPtr<TYPE, ARRAY>& ptr) const { return (m_ptr == (TPtr<TYPE>*)ptr); } bool operator!=(TYPE* pt) const { if( m_ptr ) return ((*m_ptr) != (TYPE*)pt); else if( pt ) return true; else return false; } bool operator!=(const TSmartPtr<TYPE, ARRAY>& ptr) const { return (m_ptr != (TPtr<TYPE, ARRAY>*)ptr); } TYPE* operator+(int offset) const { return (m_ptr + offset); } TYPE* operator-(int offset) const { return (m_ptr - offset); } TYPE* operator->() const { return m_ptr->GetPtr(); } TYPE& operator*() { return *(*m_ptr); } TYPE& operator[](int inx) { return (m_ptr->GetPtr())[inx]; } operator TYPE*() const { return m_ptr->GetPtr(); } ////////////////////////////////// template<class TYPE2> TSmartPtr<TYPE, ARRAY>& operator=(const TSmartPtr<TYPE2, ARRAY>& ptr) { if( (*this) == ptr ) return (*this); if( m_ptr ) -- (*m_ptr); m_ptr = (TPtr<TYPE, ARRAY>*)(TPtr<TYPE2, ARRAY>*)ptr; if( m_ptr ) ++ (*m_ptr); return (*this); } template<class TYPE2> bool operator==(TYPE2* pt) const { return ((*this) == (TYPE*)pt); } template<class TYPE2> bool operator==(const TSmartPtr<TYPE2, ARRAY>& ptr) const { return (m_ptr == (TPtr<TYPE, ARRAY>*)(TPtr<TYPE2, ARRAY>*)ptr); } template<class TYPE2> bool operator!=(TYPE2* pt) const { return ((*this) != (TYPE*)pt); } template<class TYPE2> bool operator!=(const TSmartPtr<TYPE2, ARRAY>& ptr) const { return (m_ptr != (TPtr<TYPE, ARRAY>*)(TPtr<TYPE2, ARRAY>*)ptr); } template<class TYPE2> operator TYPE2*() const { return (TYPE2*)(m_ptr->GetPtr()); } ////////////////////////////////// protected: operator TPtr<TYPE, ARRAY>*() const { return m_ptr; } }; // TSmartPtr - 智能指针类模板 结束 ////////////////////////////////////////////////////////////////// #endif // __STDCPX_SMARTPTR_H__ |
现在的智能指针不再使用map存储指针表了,另外加上了指针型别不同的拷贝,转换支持.其使用方法没有很大的变化,但是要注意一定 不能 这样使用:
1 2 3 |
TSmartPtr<int> pi = new int; int* pint = (int*)pi; TSmartPtr<int> pj = pint; // 此处这样使用会在pj析构时将pint删除两次 |
而原来的代码版本即使这样使用也不会出问题.
以上代码在Microsoft Visual C++ 2005上编译通过.