上一篇我們聊到了C++ 的 auto_ptr
,有朋友說(shuō)已經(jīng)在 C++ 17
中被棄用了,感謝朋友提醒,今天我們來(lái)聊一下 C++ 11
中引入的幾個(gè)智能指針。
成都創(chuàng)新互聯(lián)專業(yè)為企業(yè)提供阿克陶網(wǎng)站建設(shè)、阿克陶做網(wǎng)站、阿克陶網(wǎng)站設(shè)計(jì)、阿克陶網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁(yè)設(shè)計(jì)與制作、阿克陶企業(yè)網(wǎng)站模板建站服務(wù),十年阿克陶做網(wǎng)站經(jīng)驗(yàn),不只是建網(wǎng)站,更提供有價(jià)值的思路和整體網(wǎng)絡(luò)服務(wù)。
unique_ptr
shared_ptr
weak_ptr
看看它們都怎么玩。
上一篇在說(shuō) auto_ptr
的時(shí)候聊過(guò)一個(gè)術(shù)語(yǔ)叫 控制權(quán)轉(zhuǎn)移
,言外之意就是下面的代碼會(huì) 訪問(wèn)違例 。
void test() {
int* i = new int(10);
auto_ptr<int> ptr1(i);
auto_ptr<int> ptr2 = ptr1; //將 ptr1 的控制臺(tái)送給了 ptr2
cout << *ptr1 << endl;
}
int main() {
test();
}
這段代碼用了賦值運(yùn)算符,可能是程序員的無(wú)心之舉,卻引來(lái)程序的崩潰,那能不能規(guī)避下這種 無(wú)心
的行為呢? 當(dāng)然是可以的,屏蔽掉 auto_ptr
中的賦值運(yùn)算符不就可以了哈,C++ 中的 unique_ptr
就是這么實(shí)現(xiàn)的,可以看下源碼。
class unique_ptr {
public:
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
};
可以看到,unique_ptr 將 =,復(fù)制構(gòu)造函數(shù)
都給屏蔽了,所以再硬寫的話,必然是報(bào)錯(cuò)。
這個(gè)算是純正的 引用計(jì)數(shù)
,高級(jí)語(yǔ)言中的 引用跟蹤
經(jīng)常會(huì)拿它做比較,說(shuō)它存在循環(huán)引用等各種問(wèn)題。
在循環(huán)引用之前,先說(shuō)下它的簡(jiǎn)單用法。
void test() {
int* i = new int(10);
shared_ptr<int> ptr1(i);
shared_ptr<int> ptr2 = ptr1;
shared_ptr<int> ptr3 = ptr2;
printf("ptr.refcnt= %d, ptr2.refcnt=%d, ptr3.refcnt=%d \n",
ptr1.use_count(),
ptr2.use_count(),
ptr3.use_count());
}
int main() {
test();
}
再看下源碼,大概在內(nèi)部共同維護(hù)了對(duì) _Ref_count_base
引用。
class _Ref_count_base {
private:
_Atomic_counter_t _Uses = 1;
_Atomic_counter_t _Weaks = 1;
}
很顯然當(dāng)所有的析構(gòu)函數(shù)將 _Uses
降為 0 的時(shí)候就會(huì)對(duì) i
進(jìn)行釋放,參考源碼如下:
class shared_ptr : public _Ptr_base<_Ty> {
~shared_ptr() noexcept { // release resource
this->_Decref();
}
}
class _Ref_count_base {
void _Decref() noexcept { // decrement use count
if (_MT_DECR(_Uses) == 0) {
_Destroy();
_Decwref();
}
}
}
原理大概摸清楚了,接下來(lái)看下循環(huán)引用,它最大的問(wèn)題就是讓 _Uses
永遠(yuǎn)也不會(huì)為 0,
#include <iostream>
#include <string>
using namespace std;
class BClass;
class AClass
{
public:
int i = 10;
shared_ptr<BClass> b;
};
class BClass
{
public:
int i = 11;
shared_ptr<AClass> a;
};
void test() {
AClass* a = new AClass();
BClass* b = new BClass();
shared_ptr<AClass> aclass(a);
shared_ptr<BClass> bclass(b);
aclass->b = bclass;
bclass->a = aclass;
printf("a.refcnt=%d, b.refcnt=%d, a=%x,b=%x \n", aclass.use_count(), bclass.use_count(), &(*a), &(*b));
}
int main() {
test();
}
接下來(lái)可以在 main 方法結(jié)束的地方觀察 a,b
所有的 heap 塊的內(nèi)存內(nèi)容是否被釋放? 可以清楚的看到還在那里。。. 如下圖所示:
這就是 循環(huán)引用
造成的問(wèn)題,這時(shí)候就需要用到 weak_ptr
了。
弱引用就是它的引用不改變對(duì)原對(duì)象中 _Uses
的引用,接下來(lái)將 AClass 和 BClass 中的 shared_ptr
改成 weak_ptr
版。
class AClass
{
public:
int i = 10;
weak_ptr<BClass> b;
};
class BClass
{
public:
int i = 11;
weak_ptr<AClass> a;
};
從圖中可以看到,此時(shí) refcnt=1
, 再觀察下地址 0x007f71a8
的內(nèi)容,可以發(fā)現(xiàn)已經(jīng)被釋放啦。
好了,今天我們就聊這么多,希望對(duì)大家有幫助。
網(wǎng)站標(biāo)題:聊聊 C++ 中的幾種智能指針 (下)
文章地址:http://chinadenli.net/article40/dsoigho.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、App設(shè)計(jì)、做網(wǎng)站、虛擬主機(jī)、響應(yīng)式網(wǎng)站、App開(kāi)發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容