天天看點

支援引用計數的智能指針類模闆

智能指針算是很多人喜歡思考的一種記憶體管理方案了...雖然這種方案本身存在一些硬傷,但是在很多需要智能,且使用方式相對較簡單的場合裡應用還是比較多的.

先發一個我最初寫好的版本:

//

// TSmartPtr - 智能指針類模闆

//

// Author: 木頭雲

// Blog: http://hi.baidu.com/markl22222

// E-Mail: [email protected]

// 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 - 智能指針類模闆 結束

使用示例:

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:

//

// TSmartPtr - 智能指針類模闆

//

// Author: 木頭雲

// Blog: http://hi.baidu.com/markl22222

// E-Mail: [email protected]

// 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存儲指針表了,另外加上了指針型别不同的拷貝,轉換支援.其使用方法沒有很大的變化,但是要注意一定不能這樣使用:

TSmartPtr<int> pi = new int;

int* pint = (int*)pi;

TSmartPtr<int> pj = pint; // 此處這樣使用會在pj析構時将pint删除兩次

而原來的代碼版本即使這樣使用也不會出問題.

以上代碼在Microsoft Visual C++ 2005上編譯通過.

繼續閱讀