赞
踩
欢迎阅读本系列文章的第二篇,我们将继续探讨与 shared_ptr
相关的主题。上一篇文章我们介绍了 shared_ptr
的强大功能,但也提到了它可能面临的一个问题 —— 循环引用。当两个或多个对象之间相互持有 shared_ptr
的引用时,就会形成循环引用,导致这些对象无法被正确释放,从而引发内存泄漏。
在本文中,我们将深入讨论循环引用问题,并引入另一个智能指针类——weak_ptr
。weak_ptr
是 shared_ptr
的伙伴,它可以帮助我们解决循环引用问题,并且不会增加引用计数,以避免对象无法释放的情况。
通过学习 shared_ptr
和 weak_ptr
的组合使用,我们将能够更好地管理动态分配的对象,避免内存泄漏,并提高代码的健壮性和可维护性。敬请期待本文的剖析和示例,希望能给您带来更深入的了解和实践经验。
当使用 std::shared_ptr
时,循环引用是一种常见的问题。循环引用指的是两个或多个对象彼此持有 shared_ptr
的引用,形成一个环状依赖关系。这种情况下,即使没有外部引用指向这些对象,它们的引用计数也无法降为零,从而导致内存泄漏。
循环引用可能会导致内存泄漏的发生,因为每个对象都会持有对其他对象的引用,导致它们的引用计数无法归零。当没有外部引用指向这些对象时,它们的析构函数不会被调用,从而导致资源无法正确释放。
首先我们来看一段代码,这段代码就明显存在着循环引用。
struct ListNode { int _data; shared_ptr<ListNode> _prev; shared_ptr<ListNode> _next; ~ListNode(){ cout << "~ListNode()" << endl; } }; int main() { shared_ptr<ListNode> node1(new ListNode); shared_ptr<ListNode> node2(new ListNode); cout << node1.use_count() << endl; cout << node2.use_count() << endl; node1->_next = node2; node2->_prev = node1; cout << node1.use_count() << endl; cout << node2.use_count() << endl; return 0; }
✅循环引用分析:
node1
和node2
两个智能指针对象指向两个节点,引用计数变成1,我们不需要手动delete
。node1
的_next
指向node2
,node2
的_prev
指向node1
,引用计数变成2。node1
和node2
析构,引用计数减到1,但是_next
还指向下一个节点。但是_prev
还指向上一个节点。_next
析构了,node2
就释放了。_prev
析构了,node1
就释放了。_next
属于node
的成员,node1
释放了,_next
才会析构,而node1
由_prev
管理,_prev
属于node2
成员,所以这就叫循环引用,谁也不会释放。⭕让我们通过下面这个图片来说上面这个问题:
为了解决循环引用问题,可以使用 std::weak_ptr
。std::weak_ptr
是一种弱引用,它可以指向 std::shared_ptr
持有的对象,但不会增加对象的引用计数。这样,即使存在循环引用,通过使用 std::weak_ptr
可以打破循环引用,使对象的引用计数能够正确降为零,从而触发析构函数的调用。
std::weak_ptr
是 C++11 标准库中提供的一种弱引用智能指针,它可以指向 std::shared_ptr
所管理的对象,但不会增加对象的引用计数。因此,当使用 std::weak_ptr
时,如果 std::shared_ptr
对象被释放或者过期,std::weak_ptr
将自动失效,避免了循环引用导致的内存泄漏问题。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。