一:背景
上一篇我們聊到了C++ 的 auto_ptr ,有朋友說已經在 C++ 17 中被棄用了,感謝朋友提醒,今天我們來聊一下 C++ 11 中引入的幾個智能指標,
-
unique_ptr
-
shared_ptr
-
weak_ptr
看看它們都怎么玩,
二:三大智能指標詳解
1. unique_ptr
上一篇在說 auto_ptr 的時候聊過一個術語叫 控制權轉移,言外之意就是下面的代碼會 訪問違例 ,
void test() {
int* i = new int(10);
auto_ptr<int> ptr1(i);
auto_ptr<int> ptr2 = ptr1; //將 ptr1 的控制臺送給了 ptr2
cout << *ptr1 << endl;
}
int main() {
test();
}
這段代碼用了賦值運算子,可能是程式員的無心之舉,卻引來程式的崩潰,那能不能規避下這種 無心 的行為呢? 當然是可以的,屏蔽掉 auto_ptr 中的賦值運算子不就可以了哈,C++ 中的 unique_ptr 就是這么實作的,可以看下原始碼,
class unique_ptr {
public:
unique_ptr(const unique_ptr&) = delete;
unique_ptr& operator=(const unique_ptr&) = delete;
};
可以看到,unique_ptr 將 =,復制建構式 都給屏蔽了,所以再硬寫的話,必然是報錯,
2. shared_ptr
這個算是純正的 參考計數,高級語言中的 參考跟蹤 經常會拿它做比較,說它存在回圈參考等各種問題,
在回圈參考之前,先說下它的簡單用法,
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();
}
再看下原始碼,大概在內部共同維護了對 _Ref_count_base 參考,
class _Ref_count_base {
private:
_Atomic_counter_t _Uses = 1;
_Atomic_counter_t _Weaks = 1;
}
很顯然當所有的解構式將 _Uses 降為 0 的時候就會對 i 進行釋放,參考原始碼如下:
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();
}
}
}
原理大概摸清楚了,接下來看下回圈參考,它最大的問題就是讓 _Uses 永遠也不會為 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();
}
接下來可以在 main 方法結束的地方觀察 a,b 所有的 heap 塊的記憶體內容是否被釋放? 可以清楚的看到還在那里,,. 如下圖所示:
這就是 回圈參考 造成的問題,這時候就需要用到 weak_ptr 了,
3. weak_ptr
弱參考就是它的參考不改變對原物件中 _Uses 的參考,接下來將 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;
};
從圖中可以看到,此時 refcnt=1, 再觀察下地址 0x007f71a8 的內容,可以發現已經被釋放啦,
好了,今天我們就聊這么多,希望對大家有幫助,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/500172.html
標籤:其他
