C++11 智能指針

本文根據(jù)眾多互聯(lián)網(wǎng)博客內(nèi)容整理后形成宰衙,引用內(nèi)容的版權(quán)歸原始作者所有齐邦,僅限于學(xué)習(xí)研究使用物咳,不得用于任何商業(yè)用途。

智能指針主要有:unique_ptr, shared_ptr, weak_ptr赋咽。這3種指針組件就是采用了boost里的智能指針方案。很多有用過boost智能指針的朋友吨娜,很容易地就能發(fā)現(xiàn)它們之間的關(guān)間:

std boost 功能說明
unique_ptr scoped_ptr 獨占指針對象脓匿,并保證指針?biāo)笇ο笊芷谂c其一致
shared_ptr shared_ptr 共享指針對象,可以賦值給shared_ptr或weak_ptr宦赠。指針?biāo)笇ο笤谒械南嚓P(guān)聯(lián)的shared_ptr生命周期結(jié)束時結(jié)束陪毡,是強引用。
weak_ptr weak_ptr 它不能決定所指對象的生命周期勾扭,引用所指對象時毡琉,需要lock()成shared_ptr才能使用。

C++11將boost里的這一套納入了標(biāo)準(zhǔn)妙色。
如下為示例代碼:

//文件 test-1.cpp
#include <memory>
#include <iostream>
using namespace std;
int main(){
    unique_ptr<int> up1(new int(11));
    unique_ptr<int> up2 = up1;   //! 編譯時會出錯 [1]

    cout << *up1 << endl;
    unique_ptr<int> up3 = move(up1);  //! [2]
    cout << *up3 << endl;
    if (up1)
        cout << *up1 << endl;

    up3.reset();  //! [3]
    up1.reset();

    shared_ptr<string> sp1(make_shared<string>("Hello"));
    shared_ptr<string> sp2 = sp1;
    cout << "*sp1:" << *sp1 << endl;
    cout << "*sp2:" << *sp2 << endl;
    sp1.reset();
    cout << "*sp2:" << *sp2 << endl;

    weak_ptr<string> wp = sp2; //! [4]
    cout << "*wp.lock():" << *wp.lock() << endl;
    sp2.reset();
    cout << "*wp.lock():" << *wp.lock() << endl;  //! 運行時會出錯
    return 0;
}
//編譯命令: g++ -std=c++11 test-1.cpp

[1]: unique_ptr是禁止復(fù)制賦值的桅滋,始終保持一個 unique_ptr管理一個對象。
[2]: unique_ptr雖然不能賦值身辨,但可以通過 move()函數(shù)轉(zhuǎn)移對象的所有權(quán)丐谋。一旦被 move()了,原來的 up1則不再有效了煌珊。
[3]: reset()可以讓 unique_ptr提前釋放指針笋鄙。
[4]: 由 shared_ptr構(gòu)造一個 weak_ptr。

unique_ptr
unique_ptr(定義在中)提供了一種嚴(yán)格的語義上的所有權(quán)怪瓶,

  • 擁有它所指向的對象萧落。
  • 無法進行復(fù)制構(gòu)造践美,也無法進行復(fù)制賦值操作(譯注:也就是對其無法進行復(fù)制,我們無法得到指向同一個對象的兩個unique_ptr)找岖,但是可以進行移動構(gòu)造和移動賦值操作陨倡。
  • 保存指向某個對象的指針,當(dāng)它本身被刪除釋放的時候(例如许布,離開某個作用域)兴革,會使用給定的刪除器(deleter)刪除釋放它指向的對象。

unique_ptr的使用能夠包括:

  • 為動態(tài)申請的內(nèi)存提供異常安全
  • 將動態(tài)申請內(nèi)存的所有權(quán)傳遞給某個函數(shù)
  • 從某個函數(shù)返回動態(tài)申請內(nèi)存的所有權(quán)
  • 在容器中保存指針

“所有auto_ptr應(yīng)該已經(jīng)具有的(但是我們無法在C++98中實現(xiàn)的)功能”
unique_ptr十分依賴于右值引用和移動語義蜜唾。
下面是一段傳統(tǒng)的會產(chǎn)生不安全的異常的代碼:

X* f()
{
    X* p = new X;
    // 做一些事情 – 可能會拋出某個異常
    return p;
}

解決方法是杂曲,用一個unique_ptr 來管理這個對象的所有權(quán),由其進行這個對象的刪除釋放工作:

X* f()
{
    unique_ptr p(new X); // 或者使用{new X}袁余,但是不能 = new X
    // 做一些事情 – 可能會拋出異常
    return p.release();
}

現(xiàn)在擎勘,如果程序執(zhí)行過程中拋出了異常,unique_ptr就會(毫無疑問地)刪除釋放它所指向的對象颖榜,這是最基本的RAII棚饵。但是,除非我們真的需要返回一個內(nèi)建的指針掩完,我們可以返回一個unique_ptr噪漾,讓事情變得更好。

unique_ptr f()
{
    unique_ptr p(new X); // 或者使用{new X}且蓬,但是不能 = new X
    //做一些事情 – 可能會拋出異常
    return p; // 對象的所有權(quán)被傳遞出f()
}

現(xiàn)在我們可以這樣使用函數(shù)f():

void g()
{
    unique_ptr q = f(); // 使用移動構(gòu)造函數(shù)(move constructor)
    q->memfct(2); // 使用q
    X x = *q; // 復(fù)制指針q所指向的對象
    // …
} // 在函數(shù)退出的時候欣硼,q以及它所指向的對象都被刪除釋放

unique_ptr擁有“移動意義(move semantics)”,所以我們可以使用函數(shù)f() 返回的右值對q進行初始化恶阴,這樣就簡單地將所有權(quán)傳遞給了q诈胜。

在那些要不是為了避免不安全的異常問題(以及為了保證指針?biāo)赶虻膶ο蠖急徽_地刪除釋放),我們不可以使用內(nèi)建指針的情況下存淫,我們可以在容器中保存unique_ptr以代替內(nèi)建指針:

vector<unique_ptr<string>> vs { new string{“Doug”},
                                new string{“Adams”} };

unique_ptr可以通過一個簡單的內(nèi)建指針構(gòu)造完成耘斩,并且與內(nèi)建指針相比,兩者在使用上的差別很小桅咆。特殊情況下括授,unique_ptr并不提供任何形式的動態(tài)檢查(?)。

shared_ptr 與 weak_ptr

std::weak_ptr 是一種智能指針岩饼,它對被 std::shared_ptr 管理的對象存在非擁有性(“弱”)引用荚虚。在訪問所引用的對象前必須先轉(zhuǎn)換為 std::shared_ptr。
std::weak_ptr 用來表達(dá)臨時所有權(quán)的概念:當(dāng)某個對象只有存在時才需要被訪問籍茧,而且隨時可能被他人刪除時版述,可以使用 std::weak_ptr 來跟蹤該對象。需要獲得臨時所有權(quán)時寞冯,則將其轉(zhuǎn)換為 std::shared_ptr渴析,此時如果原來的 std::shared_ptr 被銷毀晚伙,則該對象的生命期將被延長至這個臨時的 std::shared_ptr 同樣被銷毀為止。
此外俭茧,std::weak_ptr 還可以用來避免 std::shared_ptr 的循環(huán)引用咆疗。
如下面的示例:

shared_ptr<string> s1(new string);
shared_ptr<string> s2 = s1;
weak_ptr<string> w1 = s2;

在內(nèi)存中:



s1, s2, w1 都指向一個 ptr_manage 的對象。
在該對象中有 shared_ref_count與 weak_ref_count兩個域分別記錄引用它的 shared_pt與 weak_ptr的個數(shù)母债。這個很容易辦到午磁,只要在復(fù)制構(gòu)造與賦值函數(shù)中對相當(dāng)?shù)匾弥颠M行加1,在析構(gòu)中減1即可毡们。ptr_manage中的 ptr域存放真正的對象指針地址迅皇。

當(dāng) shared_ref_cnt被減為0時,自動釋放ptr指針?biāo)赶虻膶ο?/strong>衙熔。
當(dāng) shared_ref_cnt與 weak_ref_cn都變成0時登颓,才釋放ptr_manage對象
如此以來青责,只要有相關(guān)聯(lián)的 shared_ptr存在挺据,對象就存在取具。weak_ptr不影響對象的生命周期脖隶。當(dāng)用 weak_ptr訪問對象時,對象有可能已被釋放了暇检,要先 lock()产阱。

當(dāng)執(zhí)行:

s1.reset()

此時:



shared_ref_cnt由2減成了1。

再執(zhí)行:

s2.reset()

此時:



shared_ref_cnt已被減到0了块仆,ptr所對應(yīng)的object已被釋放构蹬,ptr被清0。此時悔据,ptr_manage依舊保留庄敛。因為 w1還需要引用它。

在最后科汗,w1也析構(gòu)了的時候:



ptr_manage中的 weak_ref_cnt被減成0藻烤,最后連 ptr_manage都釋放了。

參考資料
C++11中的智能指針
【c++11FAQ】unique_ptr
std::weak_ptr | cppreference.com

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末头滔,一起剝皮案震驚了整個濱河市怖亭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌坤检,老刑警劉巖兴猩,帶你破解...
    沈念sama閱讀 222,590評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異早歇,居然都是意外死亡倾芝,警方通過查閱死者的電腦和手機讨勤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,157評論 3 399
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來晨另,“玉大人悬襟,你說我怎么就攤上這事≌螅” “怎么了脊岳?”我有些...
    開封第一講書人閱讀 169,301評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長垛玻。 經(jīng)常有香客問我割捅,道長,這世上最難降的妖魔是什么帚桩? 我笑而不...
    開封第一講書人閱讀 60,078評論 1 300
  • 正文 為了忘掉前任亿驾,我火速辦了婚禮,結(jié)果婚禮上账嚎,老公的妹妹穿的比我還像新娘莫瞬。我一直安慰自己,他們只是感情好郭蕉,可當(dāng)我...
    茶點故事閱讀 69,082評論 6 398
  • 文/花漫 我一把揭開白布疼邀。 她就那樣靜靜地躺著,像睡著了一般召锈。 火紅的嫁衣襯著肌膚如雪旁振。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,682評論 1 312
  • 那天涨岁,我揣著相機與錄音拐袜,去河邊找鬼。 笑死梢薪,一個胖子當(dāng)著我的面吹牛蹬铺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播秉撇,決...
    沈念sama閱讀 41,155評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼甜攀,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了畜疾?” 一聲冷哼從身側(cè)響起赴邻,我...
    開封第一講書人閱讀 40,098評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎啡捶,沒想到半個月后姥敛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,638評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡瞎暑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,701評論 3 342
  • 正文 我和宋清朗相戀三年彤敛,在試婚紗的時候發(fā)現(xiàn)自己被綠了与帆。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,852評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡墨榄,死狀恐怖玄糟,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情袄秩,我是刑警寧澤阵翎,帶...
    沈念sama閱讀 36,520評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站之剧,受9級特大地震影響郭卫,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜背稼,卻給世界環(huán)境...
    茶點故事閱讀 42,181評論 3 335
  • 文/蒙蒙 一贰军、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蟹肘,春花似錦词疼、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,674評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至竹椒,卻和暖如春童太,著一層夾襖步出監(jiān)牢的瞬間米辐,已是汗流浹背胸完。 一陣腳步聲響...
    開封第一講書人閱讀 33,788評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留翘贮,地道東北人赊窥。 一個月前我還...
    沈念sama閱讀 49,279評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像狸页,于是被迫代替她去往敵國和親锨能。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,851評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 原作者:Babu_Abdulsalam 本文翻譯自CodeProject芍耘,轉(zhuǎn)載請注明出處址遇。 引入### Ooops...
    卡巴拉的樹閱讀 30,114評論 13 74
  • C++智能指針 原文鏈接:http://blog.csdn.net/xiaohu2022/article/deta...
    小白將閱讀 6,865評論 2 21
  • 1. 什么是智能指針? 智能指針是行為類似于指針的類對象斋竞,但這種對象還有其他功能倔约。 2. 為什么設(shè)計智能指針? 引...
    MinoyJet閱讀 640評論 0 1
  • C++ 智能指針詳解 一坝初、簡介由于 C++ 語言沒有自動內(nèi)存回收機制浸剩,程序員每次 new 出來的內(nèi)存都要手動 de...
    yangqi916閱讀 1,371評論 0 2
  • 導(dǎo)讀## 最近在補看《C++ Primer Plus》第六版,這的確是本好書,其中關(guān)于智能指針的章節(jié)解析的非常清晰...
    小敏紙閱讀 2,005評論 1 12