是的,weak_ptr::lock() 返回 std::shared_ptr;仅当所指对象仍存活时返回有效 shared_ptr,否则返回空指针,且 weak_ptr 无 public 构造函数转为 shared_ptr,禁止隐式转换。

weak_ptr::lock() 返回的是 shared_ptr 吗?
是的,weak_ptr::lock() 的返回值类型就是 std::shared_ptr,但它不是“无条件升级”——只有当所指向的对象**仍存活**(即至少还有一个 shared_ptr 持有该资源)时,才会返回一个有效的 shared_ptr;否则返回一个空的 shared_ptr(if (!ptr) {...} 可判空)。
这和直接构造 shared_ptr 不同:weak_ptr 本身不参与引用计数,lock() 是唯一安全获取临时强引用的方式。
为什么不能直接用 weak_ptr 构造 shared_ptr?
编译器会拒绝类似 shared_ptr 这样的写法,因为 std::weak_ptr **没有提供接受自身类型的 public 构造函数**——这是刻意设计的安全机制,防止意外延长对象生命周期或掩盖悬挂风险。
必须显式调用 lock(),让使用者意识到:这次“升级”是有条件的、可能失败的。
立即学习“C++免费学习笔记(深入)”;
常见错误现象:
- 误以为
wptr.get()能取到原始指针 → 实际编译报错,weak_ptr没有get() - 用
*wptr或wptr->xxx→ 编译失败,weak_ptr不支持解引用操作符 - 在多线程中未检查
lock()返回值就直接使用 → 可能触发空指针解引用
lock() 的典型使用场景和注意事项
最常见于观察者模式、缓存、避免循环引用后的安全访问。关键在于:每次使用前都应视为一次“竞态检查”。
正确做法:
- 调用
auto sp = wptr.lock();获取临时shared_ptr - 立即检查是否为空:
if (sp) { /* 安全使用 sp */ } - 不要反复调用
lock()多次——每次调用都是独立判断,两次之间对象可能已被析构 - 若需多次访问同一对象,应保持
sp生命周期足够长(即在作用域内复用它,而非反复lock())
示例:
std::weak_ptrwptr = std::make_shared (42); // ... 可能有其他 shared_ptr 被释放 if (auto sp = wptr.lock()) { std::cout << *sp << "\n"; // 安全 } else { std::cout << "object gone\n"; }
lock() 和 expired() 有什么区别?
expired() 等价于 lock().get() == nullptr,但只做一次原子检查,不增加引用计数;而 lock() 在检查的同时还会尝试“捕获”当前引用,成功则返回带计数的 shared_ptr。
所以:
- 如果只是想快速判断“还活着吗”,用
expired()更轻量 - 如果接下来要访问对象,必须用
lock()并检查返回值——因为expired()返回 true 后,下一毫秒对象仍可能复活(比如别的线程刚构造了新shared_ptr),反之亦然 - 不要写
if (!wptr.expired()) { auto sp = wptr.lock(); ... }—— 这中间存在竞态窗口,应直接用lock()一步到位
容易被忽略的一点:即使 lock() 成功,也不能保证对象在整个函数执行期间都存活——它只担保“此刻可安全访问”,后续行为仍需符合 RAII 和作用域规则。










