c++的智能指針之二

shared_ptr的問題

#include <iostream>
#include <string>
#include <memory>

using namespace std;

class Girl;

class Boy{
    public:
        Boy(){
             cout << "Boy 構(gòu)造函數(shù)" << endl;
        }   
    
        ~Boy(){
             cout << "~Boy 析構(gòu)函數(shù)" <<endl;
        }   

        void setGirlFriend(shared_ptr<Girl> _girlFriend){
             this->girlFriend = _girlFriend;
        }   

    private:
        shared_ptr<Girl> girlFriend;
};

class Girl{
    public:
        Girl(){
          cout << "Girl 構(gòu)造函數(shù)" <<endl;
        }   

        ~Girl(){
          cout << "~Girl 構(gòu)造函數(shù)" <<endl;
        }   
         void setBoyFriend(shared_ptr<Boy> _boyFriend){
             this->boyFriend = _boyFriend;
        }
    private:
        shared_ptr<Boy> boyFriend;
};

void useTrap(){
     shared_ptr<Boy> spBoy(new Boy());
     shared_ptr<Girl> spGirl(new Girl());

     //陷阱用法
     spBoy->setGirlFriend(spGirl);
     spGirl->setBoyFriend(spBoy);

}


int main(void){
    useTrap();

    return 0;

}

最后的運(yùn)行情況:

root@maokx:~/learn/smartPoint# g++ -std=c++11 -g test6.cpp -o test6
root@maokx:~/learn/smartPoint# ./test6
Boy 構(gòu)造函數(shù)
Girl 構(gòu)造函數(shù)
root@maokx:~/learn/smartPoint# 

發(fā)現(xiàn)沒有調(diào)用析構(gòu)函數(shù),為什么呢?
useTrap函數(shù)結(jié)束后,函數(shù)中定義的智能指針被清掉,boy和girl指針的引用計(jì)數(shù)減1,還剩下1,對(duì)象中的智能指針還是托管他們的,所以函數(shù)結(jié)束后沒有將boy和gilr指針釋放的原因就是于此。

當(dāng)我們執(zhí)行useTrap函數(shù)時(shí),注意,是沒有結(jié)束此函數(shù),boy和girl指針其實(shí)是被兩個(gè)智能指針托管的,所以他們的引用計(jì)數(shù)是2:


image.png

從圖中可知:
無法釋放的原因是:循環(huán)引用
這種情況,很像類的頭文件的循環(huán)引用,釋放spBoy,必須謝謝spGirl,釋放spGirl的話,必須釋放spBoy,這就是死循環(huán)的情況,所以這種不行。

weak_ptr指針

weak_ptr 設(shè)計(jì)的目的是為配合 shared_ptr 而引入的一種智能指針來協(xié)助 shared_ptr 工作, 它只可以從一個(gè) shared_ptr 或另一個(gè) weak_ptr 對(duì)象構(gòu)造, 它的構(gòu)造和析構(gòu)不會(huì)引起引用記數(shù)的增加或減少。 同時(shí)weak_ptr 沒有重載*和->但可以使用 lock 獲得一個(gè)可用的 shared_ptr 對(duì)象。

弱指針的使用:
weak_ptr wpGirl_1; // 定義空的弱指針
weak_ptr wpGirl_2(spGirl); // 使用共享指針構(gòu)造
wpGirl_1 = spGirl; // 允許共享指針賦值給弱指針
弱指針也可以獲得引用計(jì)數(shù);
wpGirl_1.use_count()
弱指針不支持 * 和 -> 對(duì)指針的訪問;

#include <iostream>
#include <string>
#include <memory>

using namespace std;

class Girl;

class Boy{
    public:
        Boy(){
               cout << "Boy 構(gòu)造函數(shù)" <<endl;
        }

        ~Boy(){
               cout << "~Boy 析構(gòu)函數(shù)" <<endl;
        }

        void setGirlFriend(shared_ptr<Girl> _girlFriend){
             this->girlFriend = _girlFriend;

             //在必要使用可以轉(zhuǎn)換成共享指針
             shared_ptr<Girl> sp_girl;
             sp_girl = this->girlFriend.lock();

             cout << sp_girl.use_count() <<endl;
             //使用完之后,再將共享指針NULL即可
             sp_girl = NULL;
        }

    private:
             weak_ptr<Girl> girlFriend;
};


class Girl{
                                  
   public:
        Girl(){
            cout << "Girl 構(gòu)造函數(shù)" <<endl;
        }
        ~Girl(){
            cout << "~Girl 析構(gòu)函數(shù)" << endl;
        }

        void setBoyFriend(shared_ptr<Boy> _boyFriend){
             this->boyFriend = _boyFriend;
        }

    private:
        shared_ptr<Boy> boyFriend;
};


void useTrap(){
     shared_ptr<Boy> spBoy(new Boy());
     shared_ptr<Girl> spGirl(new Girl());

     spBoy->setGirlFriend(spGirl);
     spGirl->setBoyFriend(spBoy);
}

int main(void){
    useTrap();

    return 0;

}

運(yùn)行情況:

root@maokx:~/learn/smartPoint# g++ -std=c++11 -g test7.cpp -o test7
root@maokx:~/learn/smartPoint# ./test7
Boy 構(gòu)造函數(shù)
Girl 構(gòu)造函數(shù)
3
~Girl 析構(gòu)函數(shù)
~Boy 析構(gòu)函數(shù)
root@maokx:~/learn/smartPoint# 

這樣就調(diào)用了析構(gòu)函數(shù),弱關(guān)聯(lián),就打破了相互引用的情況。
在類中使用弱指針接管共享指針,在需要使用時(shí)就轉(zhuǎn)換成共享指針去使用即可!

注意的事項(xiàng)

不要把一個(gè)原生指針給多個(gè)智能指針管理;
int *x = new int(10);
unique_ptr< int > up1(x);
unique_ptr< int > up2(x);

// 警告! 以上代碼使up1 up2指向同一個(gè)內(nèi)存,非常危險(xiǎn)
或以下形式:
up1.reset(x);
up2.reset(x);
這樣可以,引起重復(fù)釋放的問題,類似兩次delete

記得使用u.release()的返回值;
在調(diào)用u.release()時(shí)是不會(huì)釋放u所指的內(nèi)存的,這時(shí)返回值就是對(duì)這塊內(nèi)存的唯一索引,如果沒有使用這個(gè)返回值釋放內(nèi)存或是保存起來,這塊內(nèi)存就泄漏了.
這個(gè)名字很容易讓人誤解

禁止delete 智能指針get 函數(shù)返回的指針;
如果我們主動(dòng)釋放掉get 函數(shù)獲得的指針,那么智能 指針內(nèi)部的指針就變成野指針了,析構(gòu)時(shí)造成重復(fù)釋放,帶來嚴(yán)重后果!
禁止用任何類型智能指針get 函數(shù)返回的指針去初始化另外一個(gè)智能指針!
shared_ptr< int > sp1(new int(10));
// 一個(gè)典型的錯(cuò)誤用法 shared_ptr< int > sp4(sp1.get());
既然已經(jīng)托管指針了,那么,自己不要去管理了或者亂用了,就依靠托管的管理就可以了

最后的總結(jié)

智能指針雖然使用起來很方便,但是要注意使用智能指針的一些陷阱,否則會(huì)造成嚴(yán)重的內(nèi)存報(bào)錯(cuò)或者內(nèi)存泄露等問題!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容