欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C語(yǔ)言智能指針之weak_ptr淺析

 更新時(shí)間:2021年10月18日 11:34:19   作者:AlbertS  
這篇文章主要介紹了 C++11智能指針之weak_ptr詳解,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

前言

weak_ptr這個(gè)指針天生一副“小弟”的模樣,也是在C++11的時(shí)候引入的標(biāo)準(zhǔn)庫(kù),它的出現(xiàn)完全是為了彌補(bǔ)它老大shared_ptr天生有缺陷的問(wèn)題,其實(shí)相比于上一代的智能指針auto_ptr來(lái)說(shuō),新進(jìn)老大shared_ptr可以說(shuō)近乎完美,但是通過(guò)引用計(jì)數(shù)實(shí)現(xiàn)的它,雖然解決了指針獨(dú)占的問(wèn)題,但也引來(lái)了引用成環(huán)的問(wèn)題,這種問(wèn)題靠它自己是沒(méi)辦法解決的,所以在C++11的時(shí)候?qū)hared_ptr和weak_ptr一起引入了標(biāo)準(zhǔn)庫(kù),用來(lái)解決循環(huán)引用的問(wèn)題。

weak_ptr本身也是一個(gè)模板類,但是不能直接用它來(lái)定義一個(gè)智能指針的對(duì)象,只能配合shared_ptr來(lái)使用,可以將shared_ptr的對(duì)象賦值給weak_ptr,并且這樣并不會(huì)改變引用計(jì)數(shù)的值。查看weak_ptr的代碼時(shí)發(fā)現(xiàn),它主要有lock、swapreset、expiredoperator=、use_count幾個(gè)函數(shù),與shared_ptr相比多了lock、expired函數(shù),但是卻少了get函數(shù),甚至連operator* 和 operator->都沒(méi)有,可用的函數(shù)數(shù)量少的可憐,下面通過(guò)一些例子來(lái)了解一下weak_ptr的具體用法。

使用環(huán)境

1.VS2015 + Windows7(應(yīng)該是C++11標(biāo)準(zhǔn))

2.頭文件#include <memory>

3.命名空間using namespace std;

測(cè)試過(guò)程

1.weak_ptr解決shared_ptr循環(huán)引用的問(wèn)題

定義兩個(gè)類,每個(gè)類中又包含一個(gè)指向?qū)Ψ筋愋偷闹悄苤羔樧鳛槌蓡T變量,然后創(chuàng)建對(duì)象,設(shè)置完成后查看引用計(jì)數(shù)后退出,看一下測(cè)試結(jié)果:

class CB;
class CA
{
public:
    CA() { cout << "CA() called! " << endl; }
    ~CA() { cout << "~CA() called! " << endl; }
    void set_ptr(shared_ptr<CB>& ptr) { m_ptr_b = ptr; }
    void b_use_count() { cout << "b use count : " << m_ptr_b.use_count() << endl; }
    void show() { cout << "this is class CA!" << endl; }
private:
    shared_ptr<CB> m_ptr_b;
};
class CB
{
public:
    CB() { cout << "CB() called! " << endl; }
    ~CB() { cout << "~CB() called! " << endl; }
    void set_ptr(shared_ptr<CA>& ptr) { m_ptr_a = ptr; }
    void a_use_count() { cout << "a use count : " << m_ptr_a.use_count() << endl; }
    void show() { cout << "this is class CB!" << endl; }
private:
    shared_ptr<CA> m_ptr_a;
};
void test_refer_to_each_other()
{
    shared_ptr<CA> ptr_a(new CA());
    shared_ptr<CB> ptr_b(new CB());
    cout << "a use count : " << ptr_a.use_count() << endl;
    cout << "b use count : " << ptr_b.use_count() << endl;
    ptr_a->set_ptr(ptr_b);
    ptr_b->set_ptr(ptr_a);
    cout << "a use count : " << ptr_a.use_count() << endl;
    cout << "b use count : " << ptr_b.use_count() << endl;
}

測(cè)試結(jié)果如下:

CA() called!
CB() called!
a use count : 1
b use count : 1
a use count : 2
b use count : 2

通過(guò)結(jié)果可以看到,最后CA和CB的對(duì)象并沒(méi)有被析構(gòu),其中的引用效果如下圖所示,起初定義完ptr_aptr_b時(shí),只有①③兩條引用,然后調(diào)用函數(shù)set_ptr后又增加了②④兩條引用,當(dāng)test_refer_to_each_other這個(gè)函數(shù)返回時(shí),對(duì)象ptr_a和ptr_b被銷毀,也就是①③兩條引用會(huì)被斷開,但是②④兩條引用依然存在,每一個(gè)的引用計(jì)數(shù)都不為0,結(jié)果就導(dǎo)致其指向的內(nèi)部對(duì)象無(wú)法析構(gòu),造成內(nèi)存泄漏。

wk_shared_ptr

解決這種狀況的辦法就是將兩個(gè)類中的一個(gè)成員變量改為weak_ptr對(duì)象,因?yàn)閣eak_ptr不會(huì)增加引用計(jì)數(shù),使得引用形不成環(huán),最后就可以正常的釋放內(nèi)部的對(duì)象,不會(huì)造成內(nèi)存泄漏,比如將CB中的成員變量改為weak_ptr對(duì)象,代碼如下:

class CB
{
public:
    CB() { cout << "CB() called! " << endl; }
    ~CB() { cout << "~CB() called! " << endl; }
    void set_ptr(shared_ptr<CA>& ptr) { m_ptr_a = ptr; }
    void a_use_count() { cout << "a use count : " << m_ptr_a.use_count() << endl; }
    void show() { cout << "this is class CB!" << endl; }
private:
    weak_ptr<CA> m_ptr_a;
};

測(cè)試結(jié)果如下:

CA() called!
CB() called!
a use count : 1
b use count : 1
a use count : 1
b use count : 2
~CA() called!
~CB() called!

通過(guò)這次結(jié)果可以看到,CACB的對(duì)象都被正常的析構(gòu)了,引用關(guān)系如下圖所示,流程與上一例子相似,但是不同的是④這條引用是通過(guò)weak_ptr建立的,并不會(huì)增加引用計(jì)數(shù),也就是說(shuō)CA的對(duì)象只有一個(gè)引用計(jì)數(shù),而CB的對(duì)象只有2個(gè)引用計(jì)數(shù),當(dāng)test_refer_to_each_other這個(gè)函數(shù)返回時(shí),對(duì)象ptr_aptr_b被銷毀,也就是①③兩條引用會(huì)被斷開,此時(shí)CA對(duì)象的引用計(jì)數(shù)會(huì)減為0,對(duì)象被銷毀,其內(nèi)部的m_ptr_b成員變量也會(huì)被析構(gòu),導(dǎo)致CB對(duì)象的引用計(jì)數(shù)會(huì)減為0,對(duì)象被銷毀,進(jìn)而解決了引用成環(huán)的問(wèn)題。

wk_weak_ptr

2. 測(cè)試weak_ptr對(duì)引用計(jì)數(shù)的影響

其實(shí)weak_ptr本身設(shè)計(jì)的很簡(jiǎn)單,就是為了輔助shared_ptr的,它本身不能直接定義指向原始指針的對(duì)象,只能指向shared_ptr對(duì)象,同時(shí)也不能將weak_ptr對(duì)象直接賦值給shared_ptr類型的變量,最重要的一點(diǎn)是賦值給它不會(huì)增加引用計(jì)數(shù):

void test1()
{
    // 編譯錯(cuò)誤 // error C2665: “std::weak_ptr<CA>::weak_ptr”: 3 個(gè)重載中沒(méi)有一個(gè)可以轉(zhuǎn)換所有參數(shù)類型
    // weak_ptr<CA> ptr_1(new CA());
    shared_ptr<CA> ptr_1(new CA());
    cout << "ptr_1 use count : " << ptr_1.use_count() << endl; // 輸出:ptr_1 use count : 1
    shared_ptr<CA> ptr_2 = ptr_1;
    cout << "ptr_1 use count : " << ptr_1.use_count() << endl; // 輸出:ptr_1 use count : 2
    cout << "ptr_2 use count : " << ptr_2.use_count() << endl; // 輸出:ptr_1 use count : 2
    weak_ptr<CA> wk_ptr = ptr_1;
    cout << "ptr_1 use count : " << ptr_1.use_count() << endl; // 輸出:ptr_1 use count : 2
    cout << "ptr_2 use count : " << ptr_2.use_count() << endl; // 輸出:ptr_1 use count : 2
    // 編譯錯(cuò)誤
    // error C2440 : “初始化”: 無(wú)法從“std::weak_ptr<CA>”轉(zhuǎn)換為“std::shared_ptr<CA>”
    // shared_ptr<CA> ptr_3 = wk_ptr;
}

測(cè)試weak_ptr常用函數(shù)的用法

weak_ptr中只有函數(shù)lock和expired兩個(gè)函數(shù)比較重要,因?yàn)樗旧聿粫?huì)增加引用計(jì)數(shù),所以它指向的對(duì)象可能在它用的時(shí)候已經(jīng)被釋放了,所以在用之前需要使用expired函數(shù)來(lái)檢測(cè)是否過(guò)期,然后使用lock函數(shù)來(lái)獲取其對(duì)應(yīng)的shared_ptr對(duì)象,然后進(jìn)行后續(xù)操作:

void test2()
{
    shared_ptr<CA> ptr_a(new CA());     // 輸出:CA() called!
    shared_ptr<CB> ptr_b(new CB());     // 輸出:CB() called!
    cout << "ptr_a use count : " << ptr_a.use_count() << endl; // 輸出:ptr_a use count : 1
    cout << "ptr_b use count : " << ptr_b.use_count() << endl; // 輸出:ptr_b use count : 1
    weak_ptr<CA> wk_ptr_a = ptr_a;
    weak_ptr<CB> wk_ptr_b = ptr_b;
    if (!wk_ptr_a.expired())
    {
        wk_ptr_a.lock()->show();        // 輸出:this is class CA!
    }
    if (!wk_ptr_b.expired())
    {
        wk_ptr_b.lock()->show();        // 輸出:this is class CB!
    }
    // 編譯錯(cuò)誤
    // 編譯必須作用于相同的指針類型之間
    // wk_ptr_a.swap(wk_ptr_b);         // 調(diào)用交換函數(shù)
    wk_ptr_b.reset();                   // 將wk_ptr_b的指向清空
    if (wk_ptr_b.expired())
    {
        cout << "wk_ptr_b is invalid" << endl;  // 輸出:wk_ptr_b is invalid 說(shuō)明改指針已經(jīng)無(wú)效
    }
    wk_ptr_b = ptr_b;
    if (!wk_ptr_b.expired())
    {
        wk_ptr_b.lock()->show();        // 輸出:this is class CB! 調(diào)用賦值操作后,wk_ptr_b恢復(fù)有效
    }
    // 編譯錯(cuò)誤
    // 編譯必須作用于相同的指針類型之間
    // wk_ptr_b = wk_ptr_a;

    // 最后輸出的引用計(jì)數(shù)還是1,說(shuō)明之前使用weak_ptr類型賦值,不會(huì)影響引用計(jì)數(shù)
    cout << "ptr_a use count : " << ptr_a.use_count() << endl; // 輸出:ptr_a use count : 1
    cout << "ptr_b use count : " << ptr_b.use_count() << endl; // 輸出:ptr_b use count : 1
}

現(xiàn)象分析

引用計(jì)數(shù)的出現(xiàn),解決了對(duì)象獨(dú)占的問(wèn)題,但是也帶來(lái)了循環(huán)引用的困擾,使用weak_ptr可以打破這種循環(huán),當(dāng)你理不清引用關(guān)系的時(shí)候,不妨采用文中畫圖的方式來(lái)理一理頭緒,或許就會(huì)有眼前一亮的感覺(jué)。

總結(jié) weak_ptr雖然是一個(gè)模板類,但是不能用來(lái)直接定義指向原始指針的對(duì)象。weak_ptr接受shared_ptr類型的變量賦值,但是反過(guò)來(lái)是行不通的,需要使用lock函數(shù)。weak_ptr設(shè)計(jì)之初就是為了服務(wù)于shared_ptr的,所以不增加引用計(jì)數(shù)就是它的核心功能。由于不知道什么之后weak_ptr所指向的對(duì)象就會(huì)被析構(gòu)掉,所以使用之前請(qǐng)先使用expired函數(shù)檢測(cè)一下。 測(cè)試源碼

總結(jié)

本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • C語(yǔ)言中的狀態(tài)機(jī)設(shè)計(jì)深入講解

    C語(yǔ)言中的狀態(tài)機(jī)設(shè)計(jì)深入講解

    這篇文章主要給大家介紹了關(guān)于C語(yǔ)言狀態(tài)機(jī)設(shè)計(jì)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-11-11
  • C++中結(jié)構(gòu)體和Json字符串互轉(zhuǎn)的問(wèn)題詳解

    C++中結(jié)構(gòu)體和Json字符串互轉(zhuǎn)的問(wèn)題詳解

    這篇文章主要給大家介紹了關(guān)于C++中結(jié)構(gòu)體和Json字符串互轉(zhuǎn)問(wèn)題的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • 一文詳解C++11中decltype的使用

    一文詳解C++11中decltype的使用

    這篇文章主要為大家分享了C++11中decltype關(guān)鍵字的使用示例,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2023-07-07
  • Opencv透視變換綜合實(shí)例詳解

    Opencv透視變換綜合實(shí)例詳解

    這篇文章主要為大家詳細(xì)介紹了Opencv透視變換綜合實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-05-05
  • C/C++讀取大文件數(shù)據(jù)方式詳細(xì)講解

    C/C++讀取大文件數(shù)據(jù)方式詳細(xì)講解

    這篇文章主要介紹了C語(yǔ)言/C++讀取大文件數(shù)據(jù)的完整方式過(guò)程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2022-09-09
  • c語(yǔ)言排序之歸并排序(遞歸和非遞歸)

    c語(yǔ)言排序之歸并排序(遞歸和非遞歸)

    這篇文章主要介紹了?c語(yǔ)言排序之歸并排序(遞歸和非遞歸),歸并就是把兩個(gè)或多個(gè)序列合并,本文主要介紹二路歸并,下文相關(guān)資料需要的小伙伴可以參考一下
    2022-04-04
  • 算法學(xué)習(xí)入門之使用C語(yǔ)言實(shí)現(xiàn)各大基本的排序算法

    算法學(xué)習(xí)入門之使用C語(yǔ)言實(shí)現(xiàn)各大基本的排序算法

    這篇文章主要介紹了使用C語(yǔ)言實(shí)現(xiàn)各大基本的排序算法的方法,同時(shí)也對(duì)算法的選擇問(wèn)題上給出了一些建議,的朋友可以參考下
    2015-12-12
  • 原碼, 反碼與補(bǔ)碼基礎(chǔ)知識(shí)詳細(xì)介紹

    原碼, 反碼與補(bǔ)碼基礎(chǔ)知識(shí)詳細(xì)介紹

    這篇文章講解了計(jì)算機(jī)的原碼, 反碼和補(bǔ)碼. 并且進(jìn)行了深入探求了為何要使用反碼和補(bǔ)碼, 以及更進(jìn)一步的論證了為何可以用反碼, 補(bǔ)碼的加法計(jì)算原碼的減法,需要的朋友可以參考下
    2016-12-12
  • 簡(jiǎn)單聊聊C++中回調(diào)函數(shù)的實(shí)現(xiàn)

    簡(jiǎn)單聊聊C++中回調(diào)函數(shù)的實(shí)現(xiàn)

    回調(diào)函數(shù)就是一個(gè)通過(guò)函數(shù)指針調(diào)用的函數(shù),如果你把函數(shù)的指針(地址)作為參數(shù)傳遞給另一個(gè)函數(shù),當(dāng)這個(gè)指針被用來(lái)調(diào)用其所指向的函數(shù)時(shí),我們就說(shuō)這是回調(diào)函數(shù),下面這篇文章主要給大家介紹了關(guān)于C++中回調(diào)函數(shù)實(shí)現(xiàn)的相關(guān)資料,需要的朋友可以參考下
    2022-01-01
  • 深入理解C/C++中的寫時(shí)拷貝

    深入理解C/C++中的寫時(shí)拷貝

    這篇文章主要給大家介紹了C/C++中寫時(shí)拷貝的相關(guān)資料,所謂寫時(shí)拷貝也就是拖延版的深拷貝,下面文章中介紹的非常清楚,需要的朋友可以參考學(xué)習(xí),下面來(lái)一起看看吧。
    2017-03-03

最新評(píng)論