026 weak_ptr

weak_ptr 是一種不控制所指向?qū)ο笊嫫诘闹悄苤羔樕系矗赶蛴梢粋€ shared_ptr 管理的對象诗箍,將一個 weak_ptr 綁定到一個 shared_ptr 不會改變 shared_ptr 的引用計數(shù)牵敷,一旦最后一個指向?qū)ο蟮?shared_ptr 被銷毀额港,對象就會被釋放褐鸥。即使有 weak_ptr 指向?qū)ο笱恚瑢ο笠策€是會被釋放蝶棋,因此, weak_ptr 的名字抓住了這種智能指針“弱”共享對象的特點卸亮。

weak_ptr 說明
weak_ptr<T> w 空 weak_ptr 可以指向類型為 T 的對象
weak_ptr<T> w(sp) 與 shared_ptr sp 指向相同對象的 weak_ptr,T 必須能轉(zhuǎn)換為 sp 指向的類型
w = p p 可以是一個 shared_ptr 或一個 weak_ptr玩裙,賦值后 w 與 p 共享對象
w.reset() 將 w 置為空
w.use_count() 與 w 共享對象的 shared_ptr 的數(shù)量
w.expired() 若 w.use_count() 為 0兼贸,返回 true,否則返回 false
w.lock() 如果 expired 為 true吃溅,返回一個空 shared_ptr溶诞;否則返回一個指向 w 的對象的 shared_ptr

當我們創(chuàng)建一個 weak_ptr 時,要用一個 shared_ptr 來初始化它:

auto p = make_shared<int>(42);
weak_ptr<int> wp(p); //wp 弱共享 p决侈;p 的引用計數(shù)未改變

本例中 wp 和 p 指向相同的對象螺垢,由于是弱共享,創(chuàng)建 wp 不會改變 p 的引用計數(shù)赖歌;wp 指向的對象可能被釋放掉枉圃。

由于對象可能不存在,我們不能使用 weak_ptr 直接訪問對象庐冯,而必須調(diào)用 lock孽亲。此函數(shù)檢查 weak_ptr 指向的對象是否仍存在,如果存在展父,lock 返回一個指向共享對象的 shared_ptr返劲。與任何其他 shared_ptr 類似,只要此 shared_ptr 存在栖茉,它所指向的底層對象也就會一直存在篮绿。例如:

if (shared_ptr<int> np = wp.lock()) { // 如果 np 不為空則條件成立
    // 在 if 中,np 與 p 共享對象
}

在這段代碼中,只有當 lock 調(diào)用返回 true 時我們才會進入 if 語句體吕漂。在 if 中亲配,使用 np 訪問共享對象是安全的。

核查指針類

作為 weak_ptr 用途的一個展示,我們將為 StrBlob 類定義一個伴隨指針類弃榨。我們的指針類將命名為 StrBlobPtr菩收,會保存一個 weak_ptr梨睁,指向 StrBlob 的 data 成員鲸睛,這是初始化時提供給它的,通過使用 weak_ptr坡贺,不會影響一個給定的 StrBlob 所指向的 vector 的生存期官辈。但是,可以阻止用戶訪問一個不再存在的 vector 的企圖遍坟。

StrBlobPtr 會有兩個數(shù)據(jù)成員:wptr拳亿,或者為空,或者指向一個 StrBlob 中的 vector愿伴;curr肺魁,保存當前對象所表示的元素的下標,類似它的伴隨類 StrBlob隔节,我們的指針類也有一個 check 成員來檢查解引用 StrBlobPtr 是否安全:

// 對于訪問一個不存在元素的嘗試鹅经,StrBlobPtr 拋出一個異常
class StrBlobPtr {
public:
    StrBlobPtr(): curr(0) {}
    StrBlobPtr(StrBlob &a, size_t sz = 0): 
            wptr(a.data), curr(sz) {}
    std::string & deref() const;
    StrBlobPtr& incr(); // 前綴遞增
private:
    // 若檢查成功,check 返回一個指向 vector 的 shared_ptr
    std::shared_ptr<std::vector<std::string>>
            check(std::size_t, const std::string& ) const;
    // 保存一個 weak_ptr怎诫,意味看底層 vector 可能會被銷毀
    std::weak_ptr<std::vector<std::string>> wptr;
    std:size_t curr; // 在數(shù)組中的當前位置
}

默認構(gòu)造函數(shù)生成一個空的 StrBlobPtr瘾晃,其構(gòu)造函數(shù)初始化列表將 curr 顯式初始化為 0,并將 wptr 隱式初始化為一個空 weak_ptr幻妓,第二個構(gòu)造函數(shù)接受一個 StrBlob 引用和一個可選的索引值蹦误,此構(gòu)造函數(shù)初始化 wptr,令其指向給定 StrBlob 對象的 shared_ptr 中的 vector肉津,并將 curr 初始化為 sz 的值强胰。我們使用了默認參數(shù),表示默認情況下將 curr 初始化為第一個元素的下標妹沙。我們將會看到偶洋,StrBlob 的 end 成員將會用到參數(shù) sz。

值得注意的是初烘,我們不能將 StrBlobPtr 綁定到一個 const StrBlob 對象涡真。這個限制是由于構(gòu)造函數(shù)接受一個非 const StrBlob 對象的引用而導(dǎo)致的。

StrBlobPtr 的 check 成員與 StrBlob 中的同名成員不同肾筐,它還要檢查指針指向的 vector 是否還存在:

std::shared_ptr<std::vector<std::string>>
StrBlobPtr::check(std::size_t i, const std::string &msg) const {
    auto ret = wptr.lock(); // vector 還存在嗎哆料?
    if (!ret){
        throw std::runtime_error("unbound StrBlobPtr");
    }
    if (i >= ret->size()){
        throw  std::out_of_range(msg);
    }
    return ret; // 否則,返回指向 vector 的 shared_ptr
}

由于一個 weak_ptr 不參與其對應(yīng)的 shared_ptr 的引用計數(shù)吗铐,StrBlobPtr 指向的 vector 可能已經(jīng)被釋放了东亦。如果 vector 已銷毀,lock 將返回一個空指針。在本例中典阵,任何 vector 的引用都會失敗奋渔,于是拋出一個異常。否則壮啊,check 會檢查給定索引嫉鲸,如果索引值合法,check 返回從 lock 獲得的 shared_ptr歹啼。

指針操作

我們將定義名為 deref 和 incr 的函數(shù)玄渗,分別用來解引用和遞增 StrBlobPtr。

deref 成員調(diào)用 check狸眼,檢查使用 vector 是否安全以及 curr 是否在合法范圍內(nèi):

std::string& StrBlobPtr::deref() const {
    auto p = check(curr, "dereference past end");
    return (*p)[curr]; //(*p) 是對象所指向的 vector
}

如果 check 成功藤树,p 就是一個 shared_ptr,指向 StrBlobPtr 所指向的 vector拓萌。表達式 (*p)[curr] 解引用 shared_ptr 來獲得 vector岁钓,然后使用下標運算符提取并返回 curr 位置上的元素。

incr 成員也調(diào)用 check:

// 前綴遞增:返回遞增后的對象的引用
StrBlobPtr& StrBlobPtr::incr() {
    // 如果 curr 已經(jīng)指向容器的尾后位置微王,就不能遞增它
    check(curr, "increment past end of StrBlobPtr");
    ++curr; // 推進當前位置
    return *this;
}

當然屡限,為了訪問 data 成員,我們的指針類必須聲明為 StrBlob 的 friend 我們還要為 StrBlob 類定義 begin 和 end 操作骂远,返回一個指向它自身的 StrBlobPtr:

// 對于 StrBlob 中的友元聲明來說囚霸,此前置聲明是必要的
class StrBlobPtr;
class StrBlob {
    friend class StrBlobPtr;
    // 其他成員
    // 返回指向首元素和尾后元素的 StrBlobPtr
    StrBlobPtr begin() {return StrBlobPtr(*this); }
    StrBlobPtr end() {
        auto ret = StrBlobPtr(*this, data->size());
        return ret;
    }
};
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市激才,隨后出現(xiàn)的幾起案子拓型,更是在濱河造成了極大的恐慌,老刑警劉巖瘸恼,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件劣挫,死亡現(xiàn)場離奇詭異,居然都是意外死亡东帅,警方通過查閱死者的電腦和手機压固,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來靠闭,“玉大人帐我,你說我怎么就攤上這事±颍” “怎么了拦键?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長檩淋。 經(jīng)常有香客問我芬为,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任媚朦,我火速辦了婚禮氧敢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘询张。我一直安慰自己孙乖,他們只是感情好,可當我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布瑞侮。 她就那樣靜靜地躺著的圆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪半火。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天季俩,我揣著相機與錄音钮糖,去河邊找鬼。 笑死酌住,一個胖子當著我的面吹牛店归,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播酪我,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼消痛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了都哭?” 一聲冷哼從身側(cè)響起秩伞,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎欺矫,沒想到半個月后纱新,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡穆趴,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年脸爱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片未妹。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡簿废,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出络它,到底是詐尸還是另有隱情族檬,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布酪耕,位于F島的核電站导梆,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜看尼,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一递鹉、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧藏斩,春花似錦躏结、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至兆览,卻和暖如春屈溉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背抬探。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工子巾, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人小压。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓线梗,卻偏偏與公主長得像,于是被迫代替她去往敵國和親怠益。 傳聞我的和親對象是個殘疾皇子仪搔,可洞房花燭夜當晚...
    茶點故事閱讀 45,107評論 2 356

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

  • 導(dǎo)語: C++指針的內(nèi)存管理相信是大部分C++入門程序員的夢魘蜻牢,受到Boost的啟發(fā),C++11標準推出了智能指針...
    7ee72f98ad17閱讀 896評論 0 1
  • 12.1 智能指針 智能指針行為類似普通指針镀娶,但它負責自動釋放所知的對象梯码。 #include <memory> s...
    龍遁流閱讀 363評論 0 1
  • 原作者:Babu_Abdulsalam 本文翻譯自CodeProject,轉(zhuǎn)載請注明出處闯捎。 引入### Ooops...
    卡巴拉的樹閱讀 30,102評論 13 74
  • C++裸指針的內(nèi)存問題有:1秉版、空懸指針/野指針2茬祷、重復(fù)釋放3祭犯、內(nèi)存泄漏4沃粗、不配對的申請與釋放 使用智能指針可以有效...
    WalkeR_ZG閱讀 3,102評論 0 5
  • shared_ptr 類 類似 vector,智能指針也是模板。因此盼产,當我們創(chuàng)建一個智能指針時,必須提供額外的信息...
    趙者也閱讀 849評論 0 0