std::weak_ptr::lock() 是唯一安全检测对象存活的方式,返回 shared_ptr:存活则引用计数+1,销毁则返回空;不可用 expired() 或 use_count() 判断,因存在竞态或不可靠。

std::weak_ptr::lock() 是唯一安全的检测方式
直接访问 weak_ptr 所指对象是未定义行为,必须先通过 lock() 尝试升级为 shared_ptr。它返回一个 shared_ptr:若原对象仍存活,则新指针引用计数+1;若已被销毁,返回空 shared_ptr(即 if (auto p = wp.lock()) { ... } 中的 p 为 false)。
常见错误是用 wp.expired() 判断后再调用 lock() —— 这存在竞态:两次调用之间对象可能被销毁。正确做法是只调一次 lock() 并检查其返回值。
-
expired()仅等价于lock().get() == nullptr,但多一次原子操作,且无法避免竞态 - 不要对
weak_ptr解引用(如*wp或wp->foo()),编译不通过 - 不能用
get()获取原始指针——weak_ptr本身不持有所有权,get()未定义
为什么不能用 use_count() 来判断对象是否存活
use_count() 返回的是当前关联的 shared_ptr 数量,不是对象是否存活的可靠指标。即使 use_count() == 0,对象也可能尚未析构(例如正处在 shared_ptr 的析构函数中、或有 weak_ptr 仍关联控制块但无强引用);反之,use_count() > 0 只说明至少还有一个 shared_ptr 活着,不等于你关心的那个对象“还可用”。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
-
use_count()是调试辅助,不应用于逻辑分支 - 控制块(control block)生命周期独立于所管理对象:对象销毁后,控制块可能仍存在(直到所有
weak_ptr也被销毁) - 多线程下
use_count()的读取结果瞬间就可能过期,完全不可靠
典型使用场景:缓存、观察者、回调中的安全访问
在异步回调或事件通知中,常需避免因目标对象提前销毁导致崩溃。例如注册了一个成员函数回调,但宿主对象可能已在另一线程被释放。此时应存储 weak_ptr<host></host>,回调触发时先 lock():
void on_event() {
auto host = host_ref.lock(); // host_ref 是 weak_ptr<host>
if (!host) return; // 对象已销毁,跳过处理
host->handle_event();
}</host>
- 若回调可能被多次触发(如定时器、信号重复发射),每次都要重新
lock() - 不要把
lock()结果缓存为成员变量——它只是临时强引用,延长对象生命周期仅限该作用域 - 注意循环引用风险:若
Host内部又持有了指向自身的shared_ptr(比如绑定到 lambda),需用weak_ptr打破循环
容易忽略的细节:weak_ptr 构造和 reset 行为
weak_ptr 本身不参与资源管理,它的构造/赋值/重置只影响控制块的弱引用计数,不影响对象生命周期。这意味着:
- 从空
shared_ptr构造weak_ptr是合法的,但后续lock()必然失败 -
wp.reset()仅解除与控制块的关联,不触发任何析构 - 多个
weak_ptr可指向同一控制块,彼此独立;任一weak_ptr的lock()成功,都会阻止对象被回收(只要还有强引用活着) - 控制块最终销毁时机:当强引用计数和弱引用计数都降为 0 时
真正决定对象生死的,永远只有 shared_ptr 的强引用计数;weak_ptr 唯一该做的事,就是用 lock() 安全地“问一句:你现在还在吗?”——问完立刻用返回的 shared_ptr 做事,别犹豫。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










