智能指针算是很多人喜欢思考的一种内存管理方案了...虽然这种方案本身存在一些硬伤,但是在很多需要智能,且使用方式相对较简单的场合里应用还是比较多的.
先发一个我最初写好的版本:
#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 - 智能指针类模板 结束
使用示例:
以上的智能指针类解决了包括指针多次复制导致的析构删除错误等问题,利用一个静态的管理类纪录了所有当前存在的指针,每次添加新指针时就在静态指针map中登记,若当前指针已存在就将对应的引用计数加1...
不过使用这种方法管理引用计数有一个很大的缺点,就是每次添加或删除指针时必须要查找指针map,效率上会有所损失.但是这样做的好处是不会因为将普通指针赋值给智能指针而导致引用计数的管理混乱.
通常智能指针的解决方案是封装一个用于计数的指针封装类,在智能指针类创建新智能指针时new一个新的计数类并保存它的指针,当出现智能指针之间的拷贝时通过自己保存的计数类指针对计数进行操作,等同于操作了所有拥有这个计数类指针的智能指针的引用计数.这样做就不需要任何查表的操作了,但是不好的地方是一个指针引用计数类的实例并没有严格的与一个指针相绑定...但是只要严格注意使用规范(比如不要使用普通指针直接构造智能指针,在构造新智能指针时一定要使用new出来的新指针),是不会出现指针计数管理出现混乱的错误的.
在实际使用中,我还发现上面的代码还有因指针型别不同导致指针转换不方便,以及当使用类指针时此智能指针析构函数不会调用其析构函数等一些问题.
下面是一个改进版的TSmartPtr:
#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存储指针表了,另外加上了指针型别不同的拷贝,转换支持.其使用方法没有很大的变化,但是要注意一定不能这样使用:
而原来的代码版本即使这样使用也不会出问题.
以上代码在Microsoft Visual C++ 2005上编译通过.