對於上一篇提到的方法,可以不用引入輔助類,可以直接把指針封裝起來。然後,重載操作符,定義爲一個指針的行爲,使得可以像使用指針一樣使用它。這種方法叫做句柄類,查下了資料,對這個的解釋是存儲指向動態分配對象指針的類。可以在適當的時間自動刪除指向的對象,同時,它的行爲也像一個指針。由此可以看出本文標題不太合適。
同樣的先上一張圖。
2.定義一個SmartPtr對象P2,調用拷貝構造函數,此時,P1和P2的ptr指向相同的地址,pUse指向相同的地址,引用計數自加;
3.定義一個SmartPtr對象P3,調用賦值,操作符右操作數引用計數自加,左操作數自減,並判斷原引用計數是否爲0,如果是0,則刪除原ptr指針指向的地址內容,賦值ptr和pUse,指向相同的ptr和pUse
4.析構時,引用計數自減,並判斷計數值是否爲0,如果是0,則自動刪除指針對象。
示例代碼如下:
template<typename T>
class SmartPtr
{
public:
SmartPtr(T* p= 0)
:ptr(p),pUse(new size_t(1))
{}
~SmartPtr()
{
decrUse();
}
SmartPtr(const SmartPtr<T>& src)
:ptr(src.ptr),pUse(src.pUse)
{
++*pUse;
}
SmartPtr<T>& operator=(const SmartPtr<T>& rhs)
{
if (rhs.ptr != ptr)
{
++*rhs.pUse;
decrUse();
ptr = rhs.ptr;
pUse = rhs.pUse;
}
return *this;
}
T* operator->()
{
if(ptr)
return ptr;
throw std::runtime_error("access through NULL pointer");
}
const T* operator->() const
{
if(ptr)
return ptr;
throw std::runtime_error("access through NULL pointer");
}
T& operator*()
{
if(ptr)
return *ptr;
throw std::runtime_error("dereference of NULL pointer");
}
const T& operator*() const
{
if(ptr)
return *ptr;
throw std::runtime_error("dereference of NULL pointer");
}
private:
void decrUse()
{
if(--*pUse == 0)
{
delete ptr;
delete pUse;
}
}
private:
T* ptr;
size_t* pUse;
};
順便貼上一點Cocos2d的智能指針類的代碼,它使用的方式是引入輔助類,輔助類裏有引用計數,當然這個輔助類不僅限於在智能指針的使用。省略一部分代碼和註釋。class CC_DLL Ref
{
public:
void retain();
void release();
Ref* autorelease();
unsigned int getReferenceCount() const;
protected:
Ref();
public:
virtual ~Ref();
protected:
/// count of references
unsigned int _referenceCount;
friend class AutoreleasePool;
// Memory leak diagnostic data (only included when CC_USE_MEM_LEAK_DETECTION is defined and its value isn't zero)
#if CC_USE_MEM_LEAK_DETECTION
public:
static void printLeaks();
#endif
};
下面是RefPtr,Cocos2d的智能指針類
template <typename T> class RefPtr
{
public:
inline RefPtr()
:
_ptr(nullptr)
{
}
inline RefPtr(RefPtr<T> && other)
{
_ptr = other._ptr;
other._ptr = nullptr;
}
inline RefPtr(T * ptr)
:
_ptr(const_cast<typename std::remove_const<T>::type*>(ptr)) // Const cast allows RefPtr<T> to reference objects marked const too.
{
CC_REF_PTR_SAFE_RETAIN(_ptr);
}
inline RefPtr(std::nullptr_t ptr)
:
_ptr(nullptr)
{
}
inline RefPtr(const RefPtr<T> & other)
:
_ptr(other._ptr)
{
CC_REF_PTR_SAFE_RETAIN(_ptr);
}
inline ~RefPtr()
{
CC_REF_PTR_SAFE_RELEASE_NULL(_ptr);
}
inline RefPtr<T> & operator = (const RefPtr<T> & other)
{
if (other._ptr != _ptr)
{
CC_REF_PTR_SAFE_RETAIN(other._ptr);
CC_REF_PTR_SAFE_RELEASE(_ptr);
_ptr = other._ptr;
}
return *this;
}
inline RefPtr<T> & operator = (RefPtr<T> && other)
{
if (&other != this)
{
CC_REF_PTR_SAFE_RELEASE(_ptr);
_ptr = other._ptr;
other._ptr = nullptr;
}
return *this;
}
inline RefPtr<T> & operator = (T * other)
{
if (other != _ptr)
{
CC_REF_PTR_SAFE_RETAIN(other);
CC_REF_PTR_SAFE_RELEASE(_ptr);
_ptr = const_cast<typename std::remove_const<T>::type*>(other); // Const cast allows RefPtr<T> to reference objects marked const too.
}
return *this;
}
inline RefPtr<T> & operator = (std::nullptr_t other)
{
CC_REF_PTR_SAFE_RELEASE_NULL(_ptr);
return *this;
}
// Note: using reinterpret_cast<> instead of static_cast<> here because it doesn't require type info.
// Since we verify the correct type cast at compile time on construction/assign we don't need to know the type info
// here. Not needing the type info here enables us to use these operations in inline functions in header files when
// the type pointed to by this class is only forward referenced.
inline operator T * () const { return reinterpret_cast<T*>(_ptr); }
inline T & operator * () const
{
CCASSERT(_ptr, "Attempt to dereference a null pointer!");
return reinterpret_cast<T&>(*_ptr);
}
inline T * operator->() const
{
CCASSERT(_ptr, "Attempt to dereference a null pointer!");
return reinterpret_cast<T*>(_ptr);
}
inline T * get() const { return reinterpret_cast<T*>(_ptr); }
inline bool operator == (const RefPtr<T> & other) const { return _ptr == other._ptr; }
inline bool operator == (const T * other) const { return _ptr == other; }
inline bool operator == (typename std::remove_const<T>::type * other) const { return _ptr == other; }
inline bool operator == (const std::nullptr_t other) const { return _ptr == other; }
inline bool operator != (const RefPtr<T> & other) const { return _ptr != other._ptr; }
inline bool operator != (const T * other) const { return _ptr != other; }
inline bool operator != (typename std::remove_const<T>::type * other) const { return _ptr != other; }
inline bool operator != (const std::nullptr_t other) const { return _ptr != other; }
inline bool operator > (const RefPtr<T> & other) const { return _ptr > other._ptr; }
inline bool operator > (const T * other) const { return _ptr > other; }
inline bool operator > (typename std::remove_const<T>::type * other) const { return _ptr > other; }
inline bool operator > (const std::nullptr_t other) const { return _ptr > other; }
inline bool operator < (const RefPtr<T> & other) const { return _ptr < other._ptr; }
inline bool operator < (const T * other) const { return _ptr < other; }
inline bool operator < (typename std::remove_const<T>::type * other) const { return _ptr < other; }
inline bool operator < (const std::nullptr_t other) const { return _ptr < other; }
inline bool operator >= (const RefPtr<T> & other) const { return _ptr >= other._ptr; }
inline bool operator >= (const T * other) const { return _ptr >= other; }
inline bool operator >= (typename std::remove_const<T>::type * other) const { return _ptr >= other; }
inline bool operator >= (const std::nullptr_t other) const { return _ptr >= other; }
inline bool operator <= (const RefPtr<T> & other) const { return _ptr <= other._ptr; }
inline bool operator <= (const T * other) const { return _ptr <= other; }
inline bool operator <= (typename std::remove_const<T>::type * other) const { return _ptr <= other; }
inline bool operator <= (const std::nullptr_t other) const { return _ptr <= other; }
inline operator bool() const { return _ptr != nullptr; }
inline void reset()
{
CC_REF_PTR_SAFE_RELEASE_NULL(_ptr);
}
inline void swap(RefPtr<T> & other)
{
if (&other != this)
{
Ref * tmp = _ptr;
_ptr = other._ptr;
other._ptr = tmp;
}
}
/**
* This function assigns to this RefPtr<T> but does not increase the reference count of the object pointed to.
* Useful for assigning an object created through the 'new' operator to a RefPtr<T>. Basically used in scenarios
* where the RefPtr<T> has the initial ownership of the object.
*
* E.G:
* RefPtr<cocos2d::Image> image;
* image.weakAssign(new cocos2d::Image());
*
* Instead of:
* RefPtr<cocos2d::Image> image;
* image = new cocos2d::Image();
* image->release(); // Required because new'd object already has a reference count of '1'.
*/
inline void weakAssign(const RefPtr<T> & other)
{
CC_REF_PTR_SAFE_RELEASE(_ptr);
_ptr = other._ptr;
}
private:
Ref * _ptr;
};