weak_ptr源碼分析

來源:互聯網
上載者:User

之前分析了shared_ptr的架構,這次來說一下shared_ptr的兄弟weak_ptr,它們常常是一起出現的。

weak_ptr顧名思義就是弱指標,它不會增加對象的引用計數,欸有重載operator*和operator->,使用時,應當通過weak_ptr的lock函數構造一個shared_ptr。

作用:防止循環參考(以後部落格分析)。應用:在enable_shared_from_this類中,它有一個weak_ptr weak_this_成員。當物件建構完成後,在類成員函數內部可以調用shared_from_this獲得該對象自身類型的shared_ptr。千萬不要在建構函式裡調用share_from_this,因為this還沒有完全構造出來,此時無法根據this構造一個正確的weak_ptr。
weak_ptr源碼

template<class T> class weak_ptr{private:    // Borland 5.5.1 specific workarounds    typedef weak_ptr<T> this_type;public:    typedef typename boost::detail::sp_element< T >::type element_type;    //pn是weak_count,而不是shared_count,所以weak_ptr不會引起指標引用計數增加。    weak_ptr() BOOST_NOEXCEPT : px(0), pn() // never throws in 1.30+    {    }//  generated copy constructor, assignment, destructor are fine...//如果    定義"BOOST沒有右值引用"   為假#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )// ... except in C++0x, move disables the implicit copy    //支援copy assignment    weak_ptr( weak_ptr const & r ) BOOST_NOEXCEPT : px( r.px ), pn( r.pn )    {    }    weak_ptr & operator=( weak_ptr const & r ) BOOST_NOEXCEPT    {        px = r.px;        pn = r.pn;        return *this;    }#endif////  The "obvious(明顯的)" converting constructor implementation:////  template<class Y>//  weak_ptr(weak_ptr<Y> const & r): px(r.px), pn(r.pn) // never throws//  {//  }////  has a serious problem.////  r.px may already have been invalidated(使無效). The px(r.px)//  conversion may require(需要) access to *r.px (virtual inheritance).////  It is not possible to avoid spurious(假的,偽造的) access violations since//  in multithreaded programs r.px may be invalidated at any point.//    template<class Y>#if !defined( BOOST_SP_NO_SP_CONVERTIBLE )    weak_ptr( weak_ptr<Y> const & r, typename boost::detail::sp_enable_if_convertible<Y,T>::type = boost::detail::sp_empty() )#else    weak_ptr( weak_ptr<Y> const & r )#endif    BOOST_NOEXCEPT : px(r.lock().get()), pn(r.pn)    {        boost::detail::sp_assert_convertible< Y, T >();    }    template<class Y>    weak_ptr( weak_ptr<Y> && r ) BOOST_NOEXCEPT : px( r.lock().get() ), pn( static_cast< boost::detail::weak_count && >( r.pn ) )  //強轉為右值    {        boost::detail::sp_assert_convertible< Y, T >();        r.px = 0;    }    // for better efficiency in the T == Y case    weak_ptr( weak_ptr && r )    BOOST_NOEXCEPT : px( r.px ), pn( static_cast< boost::detail::weak_count && >( r.pn ) )    {        r.px = 0;    }    // for better efficiency in the T == Y case    weak_ptr & operator=( weak_ptr && r ) BOOST_NOEXCEPT    {        this_type( static_cast< weak_ptr && >( r ) ).swap( *this );        return *this;    }    template<class Y>    weak_ptr( shared_ptr<Y> const & r )    BOOST_NOEXCEPT : px( r.px ), pn( r.pn ) //重點weak_ptr的pn=shared_ptr的pn,也就是說weak_count=shared_count    {        boost::detail::sp_assert_convertible< Y, T >();    }#if !defined(BOOST_MSVC) || (BOOST_MSVC >= 1300)    template<class Y>    weak_ptr & operator=( weak_ptr<Y> const & r ) BOOST_NOEXCEPT    {        boost::detail::sp_assert_convertible< Y, T >();        px = r.lock().get();        pn = r.pn;        return *this;    }#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )    template<class Y>    weak_ptr & operator=( weak_ptr<Y> && r ) BOOST_NOEXCEPT    {        this_type( static_cast< weak_ptr<Y> && >( r ) ).swap( *this );        return *this;    }#endif    template<class Y>    weak_ptr & operator=( shared_ptr<Y> const & r ) BOOST_NOEXCEPT    {        boost::detail::sp_assert_convertible< Y, T >();        px = r.px;        pn = r.pn;        return *this;    }#endif    //將weak_ptr提升為shared_ptr,如果已經到期,則返回一個空shared_ptr    shared_ptr<T> lock() const BOOST_NOEXCEPT       {        return shared_ptr<T>( *this, boost::detail::sp_nothrow_tag() );   //調用shared_ptr(const weak_ptr<T>& r, sp_nothrow_tag());    }    //返回shared_ptr的引用計數,pn是weak_count類型,但是它實際上轉調它持有的sp_counted_base指標(和shared_ptr持有同一個)的use_count()函數,所以可以返回所有shared_ptr引用計數的相關資訊,下同。    long use_count() const BOOST_NOEXCEPT    {        return pn.use_count();    }    //判斷shared_ptr是否到期,也就是引用計數是否為0,如果為0,說明shared_ptr已經到期死了,返回true    bool expired() const BOOST_NOEXCEPT    {        return pn.use_count() == 0;    }    bool _empty() const // extension, not in std::weak_ptr    {        return pn.empty();    }    void reset() BOOST_NOEXCEPT // never throws in 1.30+    {        this_type().swap(*this);    }    void swap(this_type & other) BOOST_NOEXCEPT    {        std::swap(px, other.px);        pn.swap(other.pn);    }    template<typename Y>    void _internal_aliasing_assign(weak_ptr<Y> const & r, element_type * px2)    {        px = px2;        pn = r.pn;    }    template<class Y> bool owner_before( weak_ptr<Y> const & rhs ) const BOOST_NOEXCEPT    {        return pn < rhs.pn;    }    template<class Y> bool owner_before( shared_ptr<Y> const & rhs ) const BOOST_NOEXCEPT    {        return pn < rhs.pn;    }

下面是weak_count的源碼:

class weak_count{private:    sp_counted_base * pi_;    friend class shared_count;public:    weak_count(): pi_(0) // nothrow    {    }    weak_count(shared_count const & r): pi_(r.pi_) // nothrow    {        if(pi_ != 0) pi_->weak_add_ref();    }    weak_count(weak_count const & r): pi_(r.pi_) // nothrow    {        if(pi_ != 0) pi_->weak_add_ref();    }// Move support#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )    weak_count(weak_count && r): pi_(r.pi_) // nothrow    {        r.pi_ = 0;    }#endif    ~weak_count() // nothrow    {        if(pi_ != 0) pi_->weak_release();    //weak_count析構一次,就減少一次sp_count_base的計數!!!!!!    }    weak_count & operator= (shared_count const & r) // nothrow    {        sp_counted_base * tmp = r.pi_;        if( tmp != pi_ )        {            if(tmp != 0) tmp->weak_add_ref();            if(pi_ != 0) pi_->weak_release();            pi_ = tmp;        }        return *this;    }    weak_count & operator= (weak_count const & r) // nothrow    {        sp_counted_base * tmp = r.pi_;        if( tmp != pi_ )        {            if(tmp != 0) tmp->weak_add_ref();            if(pi_ != 0) pi_->weak_release();            pi_ = tmp;        }        return *this;    }    void swap(weak_count & r) // nothrow    {        sp_counted_base * tmp = r.pi_;        r.pi_ = pi_;        pi_ = tmp;    }    long use_count() const // nothrow    {        return pi_ != 0? pi_->use_count(): 0;    }    bool empty() const // nothrow    {        return pi_ == 0;    }    friend inline bool operator==(weak_count const & a, weak_count const & b)    {        return a.pi_ == b.pi_;    }    friend inline bool operator<(weak_count const & a, weak_count const & b)    {        return std::less<sp_counted_base *>()(a.pi_, b.pi_);    }};//在這裡初始化shared_count中的那兩個函數,即利用wakt_count的sp_count_base初始化share_count的sp_count_base,它們是共用的//這是在調用weak_ptr的lock函數用weak_ptr構造shared_ptr,然後調用本函數的inline shared_count::shared_count( weak_count const & r ): pi_( r.pi_ ){    if( pi_ == 0 || !pi_->add_ref_lock() )    {        boost::throw_exception( boost::bad_weak_ptr() );    }}inline shared_count::shared_count( weak_count const & r, sp_nothrow_tag ): pi_( r.pi_ ){    if( pi_ != 0 && !pi_->add_ref_lock() )    {        pi_ = 0;    }}

值得注意的是,weak_ptr自身也是引用計數型智能指標,也有引用計數。weak_ptr也支援拷貝分配之類的函數。

上面代碼最後的這兩個函數是shared_count類的建構函式之一,這是使用weak_ptr的lock函數底層要調用的之一。lock函數是使用weak_ptr構造shared_ptr,這回調用shared_ptr的weak_ptr構造方法,然後shared_ptr的成員shread_count自然也要調用以weak_ptr為參數的構造方法。並且由於lock提升這個操作有多線程並發的可能,所以這裡調用的不是sp_counted_base函數的add_ref_copy(該函數是原子的,但功能簡單,不能說明提升成功或失敗),而是add_ref_lock函數,gcc版本是這樣實現的:

inline int atomic_conditional_increment( int * pw ){    spinlock_pool<1>::scoped_lock lock( pw );    int rv = *pw;    if( rv != 0 ) ++*pw;    return rv;}

首先對pw的記憶體進行上鎖,然後再進行相應操作。如果*pw不為0,則weak_ptr提升成功,增加引用計數。如果為0,說明shared_ptr對象已死,不能提升,不增加引用計數,返回0。在shared_count建構函式中(就是上面那個),取消pi_的賦值(不打算指向weak_ptr的sp_counted_base),將它重新賦為空白。

如此一來,便可實現weak_ptr提升稱為shared_ptr的安全執行緒了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.