boxmoe_header_banner_img

Hello! 欢迎来到悠悠畅享网!

文章导读

weak_ptr在什么场景使用 打破循环引用实际案例


avatar
作者 2025年8月22日 20

weak_ptr用于解决shared_ptr的循环引用问题,示例中A和B互相持有shared_ptr导致内存泄漏,将其中一个改为weak_ptr后打破循环,引用计数正常归零,对象可析构,weak_ptr通过lock()安全访问目标,常用于父子节点等场景。

weak_ptr在什么场景使用 打破循环引用实际案例

在 C++ 中,weak_ptr 主要用于解决 shared_ptr 可能引起的循环引用问题。当两个或多个对象通过 shared_ptr 相互持有对方时,引用计数永远无法归零,导致内存泄漏。weak_ptr 不增加引用计数,仅观察对象是否存在,因此适合打破这种循环。

循环引用问题示例

考虑两个类 A 和 B,它们互相持有对方的 shared_ptr:

 #include <memory> #include <iostream>  struct B; // 前向声明  struct A {     std::shared_ptr<B> b_ptr;     ~A() { std::cout << "A 被销毁n"; } };  struct B {     std::shared_ptr<A> a_ptr;     ~B() { std::cout << "B 被销毁n"; } };  int main() {     auto a = std::make_shared<A>();     auto b = std::make_shared<B>();      a->b_ptr = b;     b->a_ptr = a;      std::cout << "a 引用计数: " << a.use_count() << "n"; // 输出 2     std::cout << "b 引用计数: " << b.use_count() << "n"; // 输出 2      return 0; } 

程序结束时,A 和 B 的析构函数都不会被调用。因为 a 和 b 的引用计数都是 2(外部变量 + 对方持有),离开作用域后引用计数变为 1,无法释放。

使用 weak_ptr 打破循环

修改其中一个引用为 weak_ptr,可打破循环。通常“从属”或“反向”引用使用 weak_ptr。

 struct A {     std::shared_ptr<B> b_ptr;     ~A() { std::cout << "A 被销毁n"; } };  struct B {     std::weak_ptr<A> a_ptr; // 改为 weak_ptr     ~B() { std::cout << "B 被销毁n"; } }; 

此时 main 函数中:

  • a 的引用计数:1(仅由 main 中的变量持有)
  • b 的引用计数:2(main 持有 + a 持有)

当 main 结束时,a 和 b 的 shared_ptr 被释放,引用计数归零,对象正常析构。

weak_ptr 的安全访问

使用 weak_ptr 时,不能直接访问对象,必须先转为 shared_ptr:

 void check_A(std::weak_ptr<A> &wp) {     if (auto sp = wp.lock()) {         // 对象仍存在,sp 是临时 shared_ptr         std::cout << "A 仍然存在n";     } else {         std::cout << "A 已被释放n";     } } 

lock() 返回 shared_ptr,若对象已销毁则返回空。这保证了线程安全和生命周期管理。

基本上就这些。weak_ptr 不参与所有权,只观察,是打破 shared_ptr 循环引用的标准做法。常见于父子节点、观察者模式、缓存等场景。不复杂但容易忽略,用对了能避免内存泄漏。



评论(已关闭)

评论已关闭