shared_ptr因循环引用导致内存泄漏,weak_ptr可打破循环。例如类A和B互相持有shared_ptr时,引用计数无法归零;将其中一个改为weak_ptr后,不增加引用计数,对象可正常析构,避免泄漏。实际中建议父对象用shared_ptr管理子对象,子对象用weak_ptr回指,观察者模式也适用此原则,访问weak_ptr应使用lock()获取临时shared_ptr,确保安全。

在使用C++智能指针时,shared_ptr 能自动管理对象生命周期,避免内存泄漏。但当两个或多个对象通过 shared_ptr 相互引用时,容易出现循环引用问题,导致内存无法释放。这时就需要用到 weak_ptr 来打破循环。
循环引用的问题
考虑两个类 A 和 B,它们各自持有一个指向对方的 shared_ptr:
class B; // 前向声明class A {
public:
std::shared_ptr ptr;
~A() { std::cout };
class B {
public:
std::shared_ptr ptr;
~B() { std::cout };
如果这样使用:
auto a = std::make_shared();auto b = std::make_shared();
a->ptr = b;
b->ptr = a;
此时 a 和 b 的引用计数都为2。离开作用域后,a 和 b 各自的引用计数减1,但仍为1,析构函数不会被调用,造成内存泄漏。
立即学习“C++免费学习笔记(深入)”;
weak_ptr 的作用
weak_ptr 是一种弱引用指针,它不增加对象的引用计数。它可以指向一个由 shared_ptr 管理的对象,但不会阻止该对象被销毁。
weak_ptr 常用于观察资源是否存在,需通过 lock() 方法获取一个临时的 shared_ptr 来安全访问对象:
- 若对象仍存在,lock() 返回有效的 shared_ptr
- 若对象已销毁,lock() 返回空 shared_ptr
用 weak_ptr 打破循环
修改上面的例子,将其中一个 shared_ptr 改为 weak_ptr:
class B; // 前向声明class A {
public:
std::shared_ptr ptr;
~A() { std::cout };
class B {
public:
std::weak_ptr ptr; // 改为 weak_ptr
~B() { std::cout };
现在 B 持有对 A 的弱引用。当 a 和 b 被创建并相互赋值后:
- A 持有 B 的 shared_ptr,B 的引用计数为1
- B 持有 A 的 weak_ptr,A 的引用计数仍为1(weak_ptr 不增引用)
当离开作用域时,a 和 b 的引用计数变为0,对象正常析构,不再泄漏。
实际使用建议
在设计有父子关系或监听机制的类时,注意引用方向:
- 父对象用 shared_ptr 持有子对象
- 子对象用 weak_ptr 回引父对象
- 观察者模式中,观察者用 weak_ptr 指向被观察者
访问 weak_ptr 时始终使用 lock(),确保线程安全和对象有效性。
基本上就这些。weak_ptr 不复杂,但能有效解决 shared_ptr 的循环依赖问题,是智能指针体系中不可或缺的一环。









