enable_shared_from_this

http://blog.csdn.net/cangyingzhijia/article/details/12586317
使用情景 :當類對象被 shared_ptr 管理時,須要在類本身定義的函數裏把當前類對象做爲參數傳給其餘函數時,這時須要傳遞一個 shared_ptr ,不然就不能保持 shared_ptr 管理這個類對象的語義( 由於有一個 raw pointer 指向這個類對象,而 shared_ptr 對類對象的這個引用沒有計數,頗有可能 shared_ptr 已經把類對象資源釋放了,而那個調用函數還在使用類對象——顯然,這確定會產生錯誤 )。
 
很好奇這個模板類的實現。
 
先看看怎麼使用
 
對一個類 A ,當咱們但願使用 shared_ptr 來管理其類對象時,並且須要在本身定義的函數裏把類對象 shared_ptr ( 爲何不用普通指針,當咱們使用智能指針管理資源時,必須統一使用智能指針,而不能在某些地方使用智能指針某些地方使用 raw pointer ,不然不能保持智能指針的語義,從而產生各類錯誤 )傳給其餘函數時,可讓類 A 從 enable_shared_from_this 繼承:
 
class A : public boost::enable_shared_from_this<A> {
};
 
而後在類 A 中須要傳遞類對象自己 shared_ptr 的地方使用 shared_from_this 函數來得到指向自身的 shared_ptr 。
 
一個很是有表明性的例子:
 
 
另《Beyond the C++ Standard Library》 shared_ptr 節也有很簡單明瞭的例子。
 
實現原理
 
首先要考慮的是:在類對象自己當中不能存儲類對象自己的 shared_ptr ,不然類對象 shared_ptr 永遠也不會爲0了,從而這些資源永遠不會釋放,除非程序結束。
 
其次:類對象確定是外部函數經過某種機制分配的,並且一經分配當即交給 shared_ptr 管理( 再次強調一遍:給 shared_ptr 管理的資源必須在分配時交給 shared_ptr  ),並且之後凡是須要共享使用類對象的地方必須使用這個 shared_ptr 看成右值來構造產生或者拷貝產生另外一個 shared_ptr 從而達到共享使用的目的。
 
有了以上兩點的限制,要實現咱們的目標( 即在類對象內部使用類對象的 shared_ptr  )有如下兩種方案:
 
一、類對象的外部 shared_ptr 做爲函數參數傳給類的須要引用類對象自身的函數——顯然,這種方法很醜陋,並且並非全部的狀況均可行( 如在外部 shared_ptr 不可見的做用域中就不行 );
 
二、類對象自身存儲某種信息,在須要自身 shared_ptr 時來產生一個臨時的 shared_ptr 。
 
顯然,第2種方法更優雅(對於用戶來講),關鍵是信息怎麼存儲?
 
對了, weak_ptr !
 
實際上, boost 中就是這樣實現的。
 
但如今的問題是:什麼時候初始化這個 weak_ptr ?由於類對象生成時尚未生成相應的用來管理這個對象的 shared_ptr 。
 
boost 1.39.0 中是這樣實現的:
 
首先生成類 A :會依次調用 enable_shared_from_this 的構造函數(定義爲 protected ),以及類 A 的構造函數。在調用 enable_shared_from_this 的構造函數時,會初始化定義在 enable_shared_from_this 中的 weak_ptr (調用其默認構造函數),這時這個 weak_ptr 是無效的(或者說不指向任何對象)。
 
接着:外部程序會把指向類 A 對象的指針做爲初始化參數來初始化一個 shared_ptr 。
 
如今來看看 shared_ptr 是如何初始化的, shared_ptr 定義了以下構造函數:
 
template<class Y>
    explicit shared_ptr( Y * p ): px( p ), pn( p ) 
    {
        boost::detail::sp_enable_shared_from_this( this, p, p );
    }
 
裏面調用了  boost::detail::sp_enable_shared_from_this :
 
template< class X, class Y, class T >
 inline void sp_enable_shared_from_this( boost::shared_ptr<X> const * ppx,
 Y const * py, boost::enable_shared_from_this< T > const * pe )
{
    if( pe != 0 )
    {
        pe->_internal_accept_owner( ppx, const_cast< Y* >( py ) );
    }
}
 
裏面又調用了 enable_shared_from_this 的 _internal_accept_owner :
 
template<class X, class Y> void _internal_accept_owner( shared_ptr<X> const * ppx, Y * py ) const
    {
        if( weak_this_.expired() )
        {
            weak_this_ = shared_ptr<T>( *ppx, py );
        }
    }
 
而在這裏對 enable_shared_from_this 的成員 weak_ptr 進行拷貝賦值,使得整個 weak_ptr 做爲類對象  shared_ptr 的一個觀察者。
 
這時,當類對象自己須要自身的 shared_ptr 時,就能夠從這個 weak_ptr 來生成一個了。
 
原來如此。
本站公眾號
   歡迎關注本站公眾號,獲取更多信息