
std::weak_ptr 怎么破掉 shared_ptr 的循环引用?
它不增加引用计数,只“观察”shared_ptr 管理的对象是否还活着。只要把循环中的一方换成 weak_ptr,就能让引用计数在逻辑上“断开一环”。
典型场景:A 持有 shared_ptr<B>,B 也持有 shared_ptr<A> → 析构永远不触发。改成 B 持有 weak_ptr<A>,A 销毁时 B 的 weak_ptr 自动失效,B 也能正常析构。
- 必须用
lock()转成shared_ptr才能安全访问对象,返回空shared_ptr表示目标已销毁 - 不能直接解引用
weak_ptr(没有operator*或operator->) -
expired()只是lock().get() == nullptr的快捷写法,本质没区别
观察者模式里 weak_ptr 放在哪一层最稳妥?
放在观察者(Observer)对被观察者(Subject)的引用上,而不是反过来。因为 Subject 通常生命周期更长、管理更中心化;Observer 更可能是临时注册、随时注销的短生命周期对象。
错误做法:Subject 用 weak_ptr<Observer> 存注册列表 → Observer 销毁后 Subject 还在遍历,lock() 失败得挨个判空,逻辑臃肿。
立即学习“C++免费学习笔记(深入)”;
- 推荐结构:Observer 内部用
weak_ptr<Subject>持有被观察目标 - 每次回调前调用
if (auto sp = subject_wp.lock()) { /* 使用 sp */ } - Subject 注册/注销只需存裸指针或
shared_ptr,不参与 Observer 生命周期管理
lock() 失败后该不该重试或缓存?
不该。一旦 lock() 返回空 shared_ptr,说明对象已经析构,重试无意义;缓存 shared_ptr 反而可能延长对象寿命,违背 weak_ptr 初衷。
常见误用:在成员变量里缓存 shared_ptr 避免反复 lock() → 如果 Subject 在两次调用间析构,缓存的 shared_ptr 会阻止其释放,造成延迟泄漏。
- 每次需要访问时都调用
lock() - 如果要多次使用,就用局部
auto sp = wp.lock(); if (!sp) return;把检查和绑定写在一起 - 不要跨函数边界传递或保存这个
shared_ptr,除非你明确需要延长生命周期
和裸指针比,weak_ptr 真的更安全吗?
是,但只在“对象可能中途销毁”且“你愿意主动检查”的前提下。它不自动解决竞态,也不替代线程同步。
典型坑:lock() 成功拿到 shared_ptr 后,对象仍可能在另一线程被析构(如果最后一个外部 shared_ptr 正好在此刻释放),但此时你的 shared_ptr 仍有效 —— 这是 RAII 保证的,不是 bug。
- 真正危险的是:用裸指针 +
delete this或手动管理,完全没保护 -
weak_ptr的安全成本是每次访问前一次原子读+判断,性能开销极小,但不可省略 - 多线程下,
weak_ptr本身是线程安全的(拷贝/赋值/lock),但所指对象的内部状态仍需额外同步
循环引用不是靠“加个 weak_ptr”就自动消失的,关键在谁该拥有所有权、谁只是临时观察。搞错这一层,weak_ptr 只是把崩溃变成静默失效。










