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具备避免内存泄漏的功能了!!!


 

 参考:https://www.cnblogs.com/DswCnblog/p/5628314.html