C++スマートポインタ:weak_ptr実装の詳細


文書ディレクトリ
  • weak_ptr記述
  • 声明
  • 作用
  • 原理実現
  • 関数メンバー
  • を使用
  • まとめ
  • weak_ptr記述
    宣言
    ヘッダファイル:テンプレートクラス:template class weak_ptr宣言方式:std::weak_ptr statementさぎょう
    boostライブラリの公式説明によるとweak_ptrはshared_ptr管理の弱い参照オブジェクトのテンプレートクラス.weak_ptrのオブジェクトは、shared_ptrポインタのコンストラクション関数を使用してshared_に変換できます.ptrオブジェクト.しかし、ここでshared_ptrの構造関数パラメータは、weak_であるweak_ptrのlockメンバーを含む必要がある.ptrはshared_を取得するために使用されるptrのポインタ.
    これでshared_ptrがマルチスレッド中に破棄された場合shared_ptr::reset,weak_ptrのlockメンバーはshared_を保持できます.ptrのメンバーは、現在のshared_までptrは正常に終了します.そうしないと、非常に危険なメモリ漏れが発生します.lock()メンバーの役割については、次のコードで説明します.
    shared_ptr<int> p(new int(5));
    weak_ptr<int> q(p);
    
    // some time later
    
    if(int * r = q.get()) 
    {
        // use *r
    }
    

    マルチスレッド環境でshared_ptrは複数のスレッドで共有でき、rが使用される前にpオブジェクトはp.reset()を実行し、前の記事でshared_ptrの説明(C++スマートポインタ:shared_ptr実装の詳細)では、resetメンバーが現在のshared_をリセットします.ptrポインタの指向.この場合、現在のスレッドがrポインタを使用し続けると、空のアドレスにアクセスする異常な問題が発生するに違いない.
    以上の問題に基づいて、weak_ptr::lock()メンバーを使用してこの問題を解決する
    shared_ptr<int> p(new int(5));
    weak_ptr<int> q(p);
    
    // some time later
    
    //  weak_ptr lock     shared_ptr   
    if(shared_ptr<int> r = q.lock())
    {
        // use *r
    }
    

    lock()メンバーについて簡単に説明すると、lockメンバーが取得したshared_ptr pポインタによる一時オブジェクトの作成(weak_ptr弱引用の体現)、この一時オブジェクトは同様にpを指し、pがresetのようなdelete引用の操作を執っていても、弱引用オブジェクトはrポインタのライフサイクルが終わるまで改スマートポインタのアドレスを持っている.C++言語設計者の脳の穴に感心せざるを得ない.C++のメモリ操作の自由を保つためには、どんなに精力を費やしてもこの目標を達成して、職人の精神はやっと今日のC++をますます下層のプログラマーに好きになりました.
    原理実装
    ソースファイル/boost/smart_ptr/weak_ptr.hpp
    template<class T> class weak_ptr
    {
    private:
    
        // Borland 5.5.1 specific workarounds
        typedef weak_ptr<T> this_type;
    
  • constructor構造関数
    //      
    weak_ptr() BOOST_NOEXCEPT : px(0), pn() // never throws in 1.30+
    {
    }
    
    //      
    weak_ptr( weak_ptr const & r ) BOOST_NOEXCEPT : px( r.px ), pn( r.pn )
    {
    }
    
  • destructor構造関数、ここでweak_ptrはデフォルトの解析関数を使用し、一般的にexpiredを使用して空のオブジェクトまたはuser_を返します.count()が0の場合は補助shared_ptr解放参照
  • operator=
    1. 
     weak_ptr & operator=( weak_ptr && r ) BOOST_NOEXCEPT
    {
        this_type( static_cast< weak_ptr && >( r ) ).swap( *this );
        return *this;
    }
    
    //2.       ,  lock    Y     
    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;
    }
    
    3.
    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;
    }
    
  • weak_ptr::swapメンバー、2つのweakを交換ptrが指す内容及びアドレス
     void swap(this_type & other) BOOST_NOEXCEPT
    {
    	//     ,     
        std::swap(px, other.px);
        pn.swap(other.pn);
    }
    
  • weak_ptr::resetメンバー、・オブジェクトのアドレスと内容を再指定することは、デフォルトのコンストラクタを再使用して
    void reset() BOOST_NOEXCEPT // never throws in 1.30+
    {
    	//                    swap  
        this_type().swap(*this);
    }
    
  • を初期化するようにする.
  • weak_ptr::use_countメンバー、shared_を取得ptrオブジェクトが参照される回数.空の場合は0
    long use_count() const BOOST_NOEXCEPT
    {
        return pn.use_count();
    }
    
  • を返します.
  • weak_ptr::expiredメンバー、use_によるとcount==0でboolを返し、trueに戻るとlockでweak_を取得します.ptrのポインタは空のポインタ
     bool expired() const BOOST_NOEXCEPT
    {
        return pn.use_count() == 0;
    }
    
  • しか取得できない.
  • weak_ptr::lockメンバー、weak_ptrオブジェクトはshared_を返します.ptr.私たちが前にweakでptrの役割で説明されている、マルチスレッドアクセス防止時のshared_ptrメモリ漏れ.この時点でweak_ptrオブジェクトが取得したポインタは一時ポインタでshared_を指しますptrオブジェクトの前に指すアドレス.
    shared_ptr<T> lock() const BOOST_NOEXCEPT
    {
        return shared_ptr<T>( *this, boost::detail::sp_nothrow_tag() );
    }
    

  • 関数メンバーの使用
  • コンストラクタ
    #include 
    #include 
    
    struct C {int* data;};
    
    int main () {
      std::shared_ptr<int> sp (new int);
    
      std::weak_ptr<int> wp1;
      std::weak_ptr<int> wp2 (wp1);
      std::weak_ptr<int> wp3 (sp);
    
      std::cout << "use_count:
    "
    ; //weak_ptr shared_ptr , // , wp1 wp2 0 // wp3 shared_ptr , 1 std::cout << "wp1: " << wp1.use_count() << '
    '
    ; std::cout << "wp2: " << wp2.use_count() << '
    '
    ; std::cout << "wp3: " << wp3.use_count() << '
    '
    ; return 0; }
    の出力は、
    use_count:
    wp1: 0
    wp2: 0
    wp3: 1
    
  • である.
  • weak_ptr::operator=賦値演算子
    // weak_ptr::operator= example
    #include 
    #include 
    
    int main () {
      std::shared_ptr<int> sp1,sp2;
      std::weak_ptr<int> wp;
                                           // sharing group:
                                           // --------------
      sp1 = std::make_shared<int> (10);    // sp1
      wp = sp1;                            // sp1, wp
    
      sp2 = wp.lock();                     // sp1, wp, sp2
      sp1.reset();                         //      wp, sp2
    
      //  lock       ,      shared_ptr     
      sp1 = wp.lock();                     // sp1, wp, sp2
    
      std::cout << "*sp1: " << *sp1 << '
    '
    ; std::cout << "*sp2: " << *sp2 << '
    '
    ; return 0; }
    は、以下の
    *sp1: 10
    *sp2: 10
    
  • を出力する.
  • std::weak_ptr::swap交換ポインタアドレスおよび対応するコンテンツ
    #include 
    #include 
    
    int main () {
      std::shared_ptr<int> sp1 (new int(10));
      std::shared_ptr<int> sp2 (new int(20));
    
      std::weak_ptr<int> wp1(sp1);
      std::weak_ptr<int> wp2(sp2);
      
      std::cout << "wp1 -> " << *wp1.lock() << " " << wp1.lock() << '
    '
    ; std::cout << "wp2 -> " << *wp2.lock() << " " << wp2.lock() << '
    '
    ; // swap wp2 // // , , weak_ptr , share_ptr wp1.swap(wp2); std::cout << "sp1 -> " << *sp1 << " " << sp1 << '
    '
    ; std::cout << "sp2 -> " << *sp2 << " " << sp2 << '
    '
    ; std::cout << "wp1 -> " << *wp1.lock() << " " << wp1.lock() << '
    '
    ; std::cout << "wp2 -> " << *wp2.lock() << " " << wp2.lock() << '
    '
    ; return 0; }
    は、
    wp1 -> 10 0x11daf90
    wp2 -> 20 0x11dafd0
    sp1 -> 10 0x11daf90
    sp2 -> 20 0x11dafd0
    wp1 -> 20 0x11dafd0
    wp2 -> 10 0x11daf90
    
  • として出力.
  • std::weak_ptr::resetメンバー、実行後weak_ptrオブジェクトは、デフォルトのコンストラクション関数を再実行するように、空のオブジェクト
    // weak_ptr::reset example
    #include 
    #include 
    
    int main () {
      std::shared_ptr<int> sp (new int(10));
    
      std::weak_ptr<int> wp(sp);
    
      std::cout << "1. wp " << (wp.expired()?"is":"is not") << " expired
    "
    ; std::cout << "4. wp " << wp.use_count() << " *wp " << *wp.lock() << '
    '
    ; wp.reset(); std::cout << "2. wp " << (wp.expired()?"is":"is not") << " expired
    "
    ; std::cout << "3. sp " << sp.use_count() << " *sp " << *sp << '
    '
    ; return 0; }
    になって、次の
    1. wp is not expired
    2. wp 2 *wp 10
    3. wp is expired
    4. sp 1 *sp 10
    
  • のように出力される.
    まとめ
    shared_ptrとweak_ptrの主な違いは以下の通りである.
  • shared_ptrオブジェクトは、実際に1つのアドレスコンテンツを指すweak_を初期化することができるptrオブジェクトは、shared_によってオブジェクトを初期化する必要がある特定のアドレスを直接初期化することはできません.ptrデ初期化
  • weak_ptrはshared_に影響しませんptrの参照カウントは、弱い参照であり、一時的な参照がshared_を指すためです.ptr.shared_を使用ptrオブジェクト初期化weak_ptrはshared_をもたらさないptr参照カウントが増加します.このプロパティによってshared_を解決できます.ptrのループリファレンス問題.
  • weak_ptrは*と取得ポインタ->演算子を解参照していません.lockメンバー関数でのみ対応するshared_を取得できます.ptrインテリジェントポインタオブジェクトは、対応するアドレスとコンテンツを取得します.

  • 参照ドキュメント:http://www.cplusplus.com/reference/memory/weak_ptr/https://www.boost.org/doc/libs/1_66_0/libs/smart_ptr/doc/html/smart_ptr.html#weak_ptr