智能指標只是對指標添加引一個引用計數(_refCount).當new一個對象(即將對象賦予
ref_ptr<>變數)時_refCount加1.將ref_ptr<>變數指向其它的對象或者將其釋放(超出其
生命範圍,如局部變數)時,執行Referenced::unref(),_refCount會減1,此時如果
_refCount為0表明此對象已經沒有引用,可刪除,delete this;會調用解構函式
~Referenced(),並釋放記憶體資源.
template<class T>
class ref_ptr
{
public:
typedef T element_type;
ref_ptr() : _ptr(0) {}
ref_ptr(T* ptr) : _ptr(ptr) { if (_ptr) _ptr->ref(); }//建構函式2
inline ref_ptr& operator = (T* ptr)
{
if (_ptr==ptr) return *this;
T* tmp_ptr = _ptr;
_ptr = ptr;
if (_ptr) _ptr->ref();//添加新進的
// unref second to prevent any deletion of any object which might
// be referenced by the other object. i.e rp is child of the
// original _ptr.
if (tmp_ptr) tmp_ptr->unref();//釋放原來的
return *this;
}
T* get() const { return _ptr; }
T& operator*() const { return *_ptr; }
T* operator->() const { return _ptr; } //指標重載
T* _ptr;//類資料成員
};
void Referenced::unref()
{
...
if ( ...)
{
delete this;//會調用解構函式~Referenced(),並釋放記憶體空間
}
}
調用時:
osg::ref_ptr< osg::Group > root= new osg::Group();//建立對象,調用ref_ptr的操作
符重載函數ref_ptr& operator = (T* ptr),並將其轉化為指標指向的值. 此時記憶體中
Group的引用計數為1.
root.get();//智能指標的成員函數
osg::ref_ptr< osg::Geode > g= new osg::Geode();//記憶體中Geode的引用計數為1.
osg::ref_ptr< osg::Node > g= new osg::Geode();//ref_ptr的=操作符重載(添加新進
的,釋放原來的),上一行中的Geode的引用計數變減1,變為0,此行中建立的Node的引用計數
加1,變為1.
root->addChild( g);//智能指標指向的值的函數.此時Node的引用計數加1,變為2,因為引
用它的對象又多了一個(root).
------------------------------------------------------------
下面是一個.和->操作符兩種符號能同時使用的例子:
template<class T>
class ref_ptr
{
public:
ref_ptr(T* ptr) : _ptr(ptr) { }//建構函式
T* operator->() const { return _ptr; } //指標重載
T* get() const { return _ptr; }
protected:
T* _ptr;//類資料成員
};
class CA
{
public:
void Fun()
{
cout<< "tm\n";
}
};
class CA
{
public:
void Fun()
{
cout<< "tm\n";
}
};
int _tmain(int argc, _TCHAR* argv[])
{
ref_ptr< CA> pi( new CA);
pi.get();//對象本身就有.操作符
pi->Fun();//重載的指標操作符,如果ref_ptr類中不對指標操作符進行重載,則
會報錯.pi->後直接接T的成員函數,不能是pi->()或pi->()->Fun()等.
}
===========
附:指標操作符(->)重載:
重載operator->(),返回普通對象指標,稱為間接(Dereferencing),可形成“智能指標
”機制(即對象->函數(),如C c; c->Fun(),這需要C類對指標操作符進行重載)。這樣
方便操作,也可不用。對於obj->member;,operator ->為一元尾碼運符,可作兩種解釋
:
①如obj為指標,將尋找緊隨其後的類成員(或函數)標識符,找不到就出錯,這也是最常
見的用法。
②如obj為(定義的智能指標)對象,將解釋為(obj.operator->())->member。若obj類未
重載operator->()則出錯;當重載了X operator ->()時,如果傳回型別X為指標,則進入
①狀態;如果傳回值類型仍為對象,再進入②狀態,判斷是否可迴圈。
傳回值應該為兩種:①指標,並找到成員標誌符;②定義了operator->()的對象,將迴圈
迭代。否則出錯。
具體樣本見於《C++ Primer》14.6節與《C++ Programming Language》11.10章節。
如上面代碼中的pi->Fun();即相當於是(pi.operator->())->Fun()。