weak_ptr.lock()是唯一安全转为shared_ptr的方式,返回有效shared_ptr或空指针,必须判空后使用,否则可能访问已释放内存。

weak_ptr.lock() 是唯一安全的转换方式
直接用 shared_ptr 构造函数或强制转型(比如 static_cast)把 weak_ptr 转成 shared_ptr 会编译失败或引发未定义行为。唯一标准、线程安全、且带生命周期检查的方法就是调用 lock() —— 它返回一个 shared_ptr,如果原 weak_ptr 指向的对象还活着,就增加引用计数;否则返回空 shared_ptr。
必须检查 lock() 返回值是否为空
lock() 不抛异常,也不保证成功。常见错误是拿到返回值后直接解引用,结果触发 std::bad_weak_ptr 或访问已释放内存:
auto wp = std::weak_ptr<int>(sp); // sp 是 valid shared_ptr
auto sp2 = wp.lock(); // ✅ 正确调用
if (sp2) { // ✅ 必须判空
std::cout << *sp2;
} else {
// 对象已被销毁,不能访问
}
- 即使刚从
shared_ptr构造出weak_ptr,也不能跳过判空——因为其他线程可能刚好在你调用lock()前释放了最后一个shared_ptr -
if (wp.lock())是合法写法,但可读性差;建议拆成两步:先auto sp2 = wp.lock();,再if (sp2) - 不要用
wp.expired()替代判空:它只是等价于!wp.lock(),多一次原子操作,且仍需再调一次lock()才能用
lock() 的线程安全性与性能开销
lock() 内部对控制块做原子读,是线程安全的,多个线程并发调用不会导致数据竞争。但它有轻微性能成本:
- 每次调用都涉及原子操作和引用计数检查,高频调用(如循环内)应避免反复
lock() - 若逻辑上需要多次访问对象,应一次性
lock()并持有返回的shared_ptr,而不是每次访问都重新lock() - 不推荐在锁保护区内调用
lock()来“规避竞争”——weak_ptr本就是为无锁场景设计的,加锁反而抵消其优势
典型误用:把 weak_ptr 当普通指针用
有人试图用 weak_ptr.get() 或 &*wp.lock() 获取裸指针长期保存,这是危险的:
立即学习“C++免费学习笔记(深入)”;
-
weak_ptr.get()不存在——weak_ptr没有get()成员函数 -
&*wp.lock()得到的裸指针只在当前shared_ptr生命周期内有效;一旦该shared_ptr离开作用域,指针立即悬空 - 若需缓存地址,必须同时持有
shared_ptr(即lock()结果),不能只存裸指针
真正需要裸指针的场景极少,多数时候该重构为持有 shared_ptr 或改用观察者模式。


















