智能指针算是很多人喜欢思考的一种内存管理方案了...虽然这种方案本身存在一些硬伤,但是在很多需要智能,且使用方式相对较简单的场合里应用还是比较多的.
先发一个我最初写好的版本:
-
- #pragma once
-
- #include <map>
-
- using namespace std;
-
-
- typedef void* _Ptr;
-
- typedef void (*_DelFun)(_Ptr p);
-
-
- class CDelFunc
- {
- public:
- inline static void DelSingle(_Ptr p)
- {
- if(p) delete p;
- }
-
- inline static void DelArray(_Ptr p)
- {
- if(p) delete [] p;
- }
- };
-
-
- 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();
- }
- };
-
-
- map<_Ptr, CSmartPtrManager::_PTR> CSmartPtrManager::lst_ptr;
- CSmartPtrManager::CAutoRecycle CSmartPtrManager::auto_rec;
-
-
- 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<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:
-
- #ifndef __STDCPX_SMARTPTR_H__
- #define __STDCPX_SMARTPTR_H__
-
- #pragma once
-
-
- typedef void* _Ptr;
-
-
- template<class TYPE = _Ptr, bool ARRAY = false>
- class TPtr;
-
- 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;
- }
- };
-
-
- 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;
- }
- };
-
-
- #endif // __STDCPX_SMARTPTR_H__
现在的智能指针不再使用map存储指针表了,另外加上了指针型别不同的拷贝,转换支持.其使用方法没有很大的变化,但是要注意一定不能这样使用:
- TSmartPtr<int> pi = new int;
- int* pint = (int*)pi;
- TSmartPtr<int> pj = pint;
而原来的代码版本即使这样使用也不会出问题.
以上代码在Microsoft Visual C++ 2005上编译通过.
http://blog.csdn.net/markl22222/article/details/5308111
支持引用计数的智能指针类模板
原文:http://www.cnblogs.com/findumars/p/5017761.html