weak_ptr本身不解决循环引用,仅提供主动打破的手段;它不增加引用计数,是观察者,需配合lock()安全访问,关键在厘清所有权而非滥用。

weak_ptr 本身不解决循环引用,它只是让 shared_ptr 能「主动打破」循环引用——关键在你是否在合适位置用了它,以及是否理解 shared_ptr 的引用计数机制。
为什么 weak_ptr 不自动破环?
weak_ptr 不增加引用计数,也不参与资源生命周期管理。它只是「观察者」:可以临时升级为 shared_ptr(用 lock() 或 expired() 判断),但不会阻止对象被销毁。
常见误解是“只要把某个 shared_ptr 换成 weak_ptr 就万事大吉”,其实错在没识别谁该是「拥有者」、谁该是「观察者」。
- 父子关系中,父持有子的
shared_ptr是合理的;子若反向持父的shared_ptr,就构成循环 - 此时子应改用
weak_ptr持父,且每次访问前必须调用lock()检查有效性 - 如果子在析构时还试图通过
weak_ptr访问父(而父已销毁),会得到空shared_ptr,不是崩溃,但逻辑可能出错
典型循环引用场景与 weak_ptr 插入点
最常出问题的是双向链表节点、观察者模式、树结构中的 parent/child 关系。重点不是“能不能用 weak_ptr”,而是“在哪一层断开”。
立即学习“C++免费学习笔记(深入)”;
例如树节点定义:
struct TreeNode {
std::shared_ptr left;
std::shared_ptr right;
std::weak_ptr parent; // ✅ 这里必须是 weak_ptr
}; -
left/right是强引用:子节点生命周期由父节点控制,合理 -
parent是弱引用:避免子节点延长父节点寿命,破坏释放顺序 - 访问 parent 时必须写
if (auto p = parent.lock()) { /* use p */ },不能直接解引用parent
weak_ptr 用错反而掩盖内存泄漏
有人把所有反向指针都换成 weak_ptr,以为高枕无忧,结果发现对象提前释放或访问空指针——这不是 weak_ptr 的错,是设计没厘清所有权。
- 如果两个对象本应共存(比如一对 socket 连接的 client/server 对象),强行用
weak_ptr可能导致一个先死,另一个还在等回调 -
weak_ptr::lock()返回空shared_ptr是正常行为,不是错误,但业务逻辑必须处理这种「目标已不存在」的情况 - 调试时注意:
shared_ptr::use_count()在多线程下不可靠;真正判断是否泄漏,得结合 ASan 或 Valgrind 看实际堆块存活
循环引用的根因永远是设计层面的「所有权模糊」,weak_ptr 只是工具。最容易被忽略的一点:哪怕用了 weak_ptr,如果某处意外把 weak_ptr 升级后长期持有(比如存进全局容器),它又变回强引用,循环照旧。










