weak_ptr不能直接访问对象,因其设计初衷是不参与所有权管理,故不提供operator->或operator*;必须先调用lock()获取shared_ptr,且仅当对象存活时返回非空指针。

weak_ptr 为什么不能直接访问对象
weak_ptr 本身不持有对象所有权,它只是对 shared_ptr 管理对象的“弱观察”。所以没有 operator-> 或 operator* —— 直接调用会编译失败,比如 wp->foo() 或 *wp 都非法。
必须先调用 lock() 获得一个临时的 shared_ptr,才能安全访问。这个过程本质是原子检查:对象是否还活着。
- 如果对象已被释放,
wp.lock()返回空shared_ptr(即if (auto sp = wp.lock()) { ... }是标准写法) - 如果对象还在,返回的
shared_ptr会增加引用计数,确保在作用域内不会被意外析构 - 不要缓存
lock()的结果跨函数或异步回调——除非你明确控制生命周期
怎么用 weak_ptr 打破 shared_ptr 循环引用
循环引用是 shared_ptr 最常见的内存泄漏场景,典型如父子节点、观察者模式中的双向绑定。此时一方改用 weak_ptr 即可切断强引用链。
例如父类持有一个 shared_ptr,子类反向持有 weak_ptr:
struct Parent {
std::shared_ptr<child> child;
};
struct Child {
std::weak_ptr<parent> parent; // 不增加 Parent 的引用计数
};</parent></child>
- Child 访问 Parent 时必须写
if (auto p = parent.lock()) { p->do_something(); } - Parent 析构时,Child 的
weak_ptr自动失效,lock()返回空,不会阻止 Parent 释放 - 注意:不能把
weak_ptr存在容器里长期等待“某天它变有效”——它不延长生命周期,也不触发回调
weak_ptr::lock() 和 expired() 有什么区别
两者都用于判断所观察对象是否还存在,但语义和开销不同。
-
wp.expired()是轻量检查,只读取控制块中的引用计数(不含弱引用计数),返回bool;适合快速跳过无效情况 -
wp.lock()是原子操作:先检查再构造shared_ptr,有轻微开销;它是线程安全的,且能防止检查后对象被析构的竞态 - 绝大多数场景推荐直接用
if (auto sp = wp.lock()),比先expired()再lock()更简洁、更安全 - 仅当确定不需要访问对象(比如只做日志或统计),才用
expired()避免无谓的shared_ptr构造
weak_ptr 能不能从 raw pointer 或 unique_ptr 构造
不能。构造 weak_ptr 唯一合法方式是通过已存在的 shared_ptr(包括拷贝其内部控制块)。
-
weak_ptr✅wp(sp); -
weak_ptr❌ 编译失败wp(new T); -
weak_ptr❌wp(std::move(up)); unique_ptr不共享所有权,无法提供控制块 - 试图用
shared_ptr的get()结果去 new 一个weak_ptr也是错的——那只是裸指针,没控制块信息
如果你只有裸指针,说明本就不该用 weak_ptr;需要弱观察,就得让源头统一用 shared_ptr 管理。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











