C++weak_ptr解决shared_ptr循环引用问题

循环引用指两个对象的shared_ptr相互持有,导致引用计数无法归零而内存泄漏;weak_ptr不增加引用计数,可打破循环,通过lock()安全访问对象,常用于父子关系或双向链表中避免内存泄漏。

C++weak_ptr解决shared_ptr循环引用问题

在C++中,shared_ptr通过引用计数管理对象生命周期,但当两个或多个对象互相持有对方的shared_ptr时,会形成循环引用,导致内存无法释放。这时就需要用到weak_ptr来打破循环。

什么是循环引用?

考虑两个类A和B,每个类都持有一个指向对方的shared_ptr

 struct B; // 前向声明  struct A {     std::shared_ptr<B> ptr;     ~A() { std::cout << "A destroyedn"; } };  struct B {     std::shared_ptr<A> ptr;     ~B() { std::cout << "B destroyedn"; } }; 

如果这样使用:

 auto a = std::make_shared<A>(); auto b = std::make_shared<B>(); a->ptr = b; b->ptr = a; 

此时a和b的引用计数都是2。离开作用域后,shared_ptr会减少引用计数到1,但由于仍大于0,析构函数不会被调用,造成内存泄漏。

立即学习C++免费学习笔记(深入)”;

weak_ptr如何解决循环引用?

weak_ptrshared_ptr的观察者,它不增加引用计数。它可以指向一个由shared_ptr管理的对象,但不会阻止对象被销毁。

修改上面的例子,把其中一个shared_ptr换成weak_ptr

C++weak_ptr解决shared_ptr循环引用问题

AlibabaWOOD

阿里巴巴打造的多元电商视频智能创作平台

C++weak_ptr解决shared_ptr循环引用问题37

查看详情 C++weak_ptr解决shared_ptr循环引用问题

 struct B;  struct A {     std::shared_ptr<B> ptr;     ~A() { std::cout << "A destroyedn"; } };  struct B {     std::weak_ptr<A> ptr;  // 改为 weak_ptr     ~B() { std::cout << "B destroyedn"; } }; 

现在即使相互引用,也不会形成循环。当外部的shared_ptr离开作用域,引用计数正确归零,对象能被正常释放。

如何安全使用weak_ptr?

由于weak_ptr不保证所指对象一定存在,访问前必须检查:

  • 使用 lock() 获取临时的shared_ptr,若对象已销毁则返回空
  • 使用 expired() 判断对象是否已被释放(但有竞态风险)

推荐方式:

 std::shared_ptr<A> temp = b.ptr.lock(); if (temp) {     // 安全使用 temp     std::cout << "Object is aliven"; } else {     std::cout << "Object has been destroyedn"; } 

这样做既打破了循环引用,又能安全地访问目标对象。

基本上就这些。在设计有父子关系、双向链表或观察者模式等结构时,记得让从属方使用weak_ptr,主导方使用shared_ptr,就能有效避免内存泄漏。

c++ 作用域 red 析构函数 循环 对象 作用域

上一篇
下一篇