日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

C++智能指针:weak_ptr实现详解

發布時間:2023/11/27 生活经验 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++智能指针:weak_ptr实现详解 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

      • weak_ptr描述
        • 聲明
        • 作用
        • 原理實現
      • 函數成員使用
      • 總結

weak_ptr描述

聲明

頭文件:<memory>
模版類:template <class T> class weak_ptr
聲明方式:std::weak_ptr<type_id> statement

作用

根據boost庫的官方描述,weak_ptr是由shared_ptr管理的一種弱引用對象的模版類。weak_ptr的對象能夠使用shared_ptr指針的構造函數轉換為一個shared_ptr對象。但是這里shared_ptr的構造函數參數需要包含weak_ptr的lock成員,該成員是weak_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 laterif(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 workaroundstypedef 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成員,交換兩個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 <iostream>
    #include <memory>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:\n";//weak_ptr對象如果為經shared_ptr初始化,//它是沒有引用計數的,所以這里wp1和wp2引用計數都為0//只有wp3經過了shared_ptr初始化,它的引用計數才為1std::cout << "wp1: " << wp1.use_count() << '\n';std::cout << "wp2: " << wp2.use_count() << '\n';std::cout << "wp3: " << wp3.use_count() << '\n';return 0;
    }
    
    輸出如下:
    use_count:
    wp1: 0
    wp2: 0
    wp3: 1
    
  • weak_ptr::operator=賦值運算符
    // weak_ptr::operator= example
    #include <iostream>
    #include <memory>int main () {std::shared_ptr<int> sp1,sp2;std::weak_ptr<int> wp;// sharing group:// --------------sp1 = std::make_shared<int> (10);    // sp1wp = sp1;                            // sp1, wpsp2 = wp.lock();                     // sp1, wp, sp2sp1.reset();                         //      wp, sp2//通過lock保留的臨時指針,重新獲取到了shared_ptr共享的地址sp1 = wp.lock();                     // sp1, wp, sp2std::cout << "*sp1: " << *sp1 << '\n';std::cout << "*sp2: " << *sp2 << '\n';return 0;
    }
    
    輸出如下
    *sp1: 10
    *sp2: 10
    
  • std::weak_ptr::swap交換指針地址以及對應的內容
    #include <iostream>
    #include <memory>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() << '\n';std::cout << "wp2 -> " << *wp2.lock() << " " << wp2.lock() << '\n';//這里的swap僅僅是交換wp2的各自的指向地址//并不會直接導致對應智能指針原始指針的地址交換//根據輸出,所以很明顯,交換完成之后weak_ptr對象指向發生了變化,但是并未導致share_ptr指針的指向變化wp1.swap(wp2);std::cout << "sp1 -> " << *sp1 << " " << sp1 << '\n';std::cout << "sp2 -> " << *sp2 << " " << sp2 << '\n';std::cout << "wp1 -> " << *wp1.lock() << " " << wp1.lock() << '\n';std::cout << "wp2 -> " << *wp2.lock() << " " << wp2.lock() << '\n';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 <iostream>
    #include <memory>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\n";std::cout << "4. wp " << wp.use_count() << " *wp " << *wp.lock() << '\n';wp.reset();std::cout << "2. wp " << (wp.expired()?"is":"is not") << " expired\n";std::cout << "3. sp " << sp.use_count() << " *sp " << *sp << '\n';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主要區別如下

  1. shared_ptr對象能夠初始化實際指向一個地址內容而weak_ptr對象沒辦法直接初始化一個具體地址,它的對象需要由shared_ptr去初始化
  2. weak_ptr不會影響shared_ptr的引用計數,因為它是一個弱引用,只是一個臨時引用指向shared_ptr。即使用shared_ptr對象初始化weak_ptr不會導致shared_ptr引用計數增加。依此特性可以解決shared_ptr的循環引用問題。
  3. 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

總結

以上是生活随笔為你收集整理的C++智能指针:weak_ptr实现详解的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。