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