std::weak_ptr
避免shared_ptr內存泄漏的利器。👈
smart pointer 三兄弟性格各異。unque_ptr是獨來獨往,shared_ptr是左擁右抱,而weak_ptr生來就不是為了單打獨斗,了解之后你會發現他總是和shared_ptr出雙入對。
既然shared_ptr是智能指針,那理所應當不會發生內存泄漏,那么為什么👆還會說“避免shared_ptr內存泄漏”呢?我們不禁疑惑👇
shared_ptr怎么導致的內存泄漏?
我們知道shared_ptr的特性是:內含一個計數器(可能是計數器,也可能其他數據結構),掌握着share某對象的指針的數量(shared_ptr.use_count()可知),當計數器值為0時,它壽終正寢連帶它的對象也一起陪葬(被它的析構函數銷毀),好不霸道。但就是這么強勢的它,也有翻船(發生內存泄漏)的時候---循環引用。
看👇的例子
1 #include <iostream> 2 #include <memory> 3 using namespace std; 4 5 class B; 6 class A 7 { 8 public: 9 A() { cout << "A's constructor ..." << endl; } 10 ~A() { cout << "A's destructor ..." << endl; } 11 12 std::shared_ptr<B> b;//class A中含有指向class B的shared指針 13 }; 14 15 class B 16 { 17 public: 18 B() { cout << "B's constructor ..." << endl; } 19 ~B() { cout << "B's destructor ..." << endl; } 20 21 std::shared_ptr<A> a; //class B 中含有指向class A的shared指針 22 }; 23 25 int main() 26 { 27 std::shared_ptr<A> aa = make_shared<A>(); //aa->object A aa計數器 1 28 std::shared_ptr<B> bb = make_shared<B>(); //bb->object B bb計數器 1 29 30 aa->b = bb;// aa 計數器來到了 2 31 bb->a = aa;// bb 計數器來到了 2 32 33 return 0; 34 }
class A中含有指向class B的shared指針, class B 中含有指向class A的shared指針,這樣形成了循環引用。
我們來看輸出結果👇

可以看到,兩個類對象都進行了構造,卻沒有析構銷毀掉,發生了內存泄漏⚡⚡
為什么呢?其實,在執行完一下語句后,shared_ptr計數器就加到了2,而出了main函數作用域,其計數會-1,成為 1,不為0,所以該對象未被析構(銷毀)。
aa->b = bb;// aa 計數器來到了 2
bb->a = aa;// bb 計數器來到了 2
這可如何是好,連智能指針都出現內存泄露了,我還是回去用我的一般指針?當然不是!
❇❇weak_ptr閃亮登場❇❇
weak_ptr為什么存在?
特性:
不可使用* 和 ->訪問對象
被賦值,不會引起shared_ptr內部計數器值變化(我猜是它嚴格上來說不具備指針的能力---訪問對象)
所以,我們就可以用weak_ptr替代shared_ptr, 看👇例子。
1 #include <iostream> 2 #include <memory> 3 using namespace std; 4 5 class B; 6 class A 7 { 8 public: 9 A() { cout << "A's constructor ..." << endl; } 10 ~A() { cout << "A's destructor ..." << endl; } 11 12 std::weak_ptr<B> weak_b; 13 }; 14 15 class B 16 { 17 public: 18 B() { cout << "B's constructor ..." << endl; } 19 ~B() { cout << "B's destructor ..." << endl; } 20 21 std::weak_ptr<A> weak_a; 22 }; 23 25 int main() 26 { 27 std::shared_ptr<A> aa = make_shared<A>(); //aa->object A aa計數器 1 28 std::shared_ptr<B> bb = make_shared<B>(); //bb->object B bb計數器 1 29 30 aa->weak_b = bb; //計數器還是1哦 31 bb->weak_a = aa; //計數器還是1哦 32 33 return 0; 34 }
再來看下結果👇
object A & B都被成功析構(銷毀)了。那么循環引用導致shared_ptr發生內存泄漏的問題迎刃而解!
原因是:weak_ptr不會增加shared_ptr的計數器,從而離開mian函數作用域時,shared_ptr aa & bb 計數器都 -1 ,成為0, 具備銷毀條件,調用析構函數銷毀自己和所指對象
至此,我們終於可以說weak_ptr具備避免內存泄漏的功能了!!!