weak_ptr不能直接访问对象,因为它不持有引用计数且未重载->和*操作符;必须先调用lock()获取shared_ptr再安全访问,lock()线程安全并避免竞态,expired()仅轻量判存活但存在竞态风险。

weak_ptr 为什么不能直接访问对象
因为 weak_ptr 不持有对象的引用计数,它只是“观察”一个由 shared_ptr 管理的对象。直接用 -> 或 * 会编译失败——weak_ptr 没有重载这些操作符。
正确做法是先调用 lock() 获取一个临时的 shared_ptr:
std::shared_ptr<int> sp = std::make_shared<int>(42);
std::weak_ptr<int> wp = sp;
auto locked = wp.lock(); // 返回 shared_ptr,若原对象已销毁则为空
if (locked) {
std::cout
<ul>
<li>
<code>lock()</code> 是线程安全的,返回的 <code>shared_ptr</code> 会增加引用计数(仅当对象还存在)</li>
<li>不要用 <code>expired()</code> + <code>lock()</code> 两次检查——竞态条件下可能失效,直接用 <code>lock()</code> 判空更可靠</li>
<li>避免长期持有 <code>weak_ptr</code> 后反复调用 <code>lock()</code>:每次调用都有原子操作开销</li>
</ul>
<h3>循环引用破除:weak_ptr 的典型场景</h3>
<p>两个 <code>shared_ptr</code> 相互持有会导致引用计数永远不为 0,内存无法释放。这时让其中一方改用 <code>weak_ptr</code>。</p>
<p>比如父子节点结构:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master"><img
src="https://img.php.cn/upload/skill/000/000/081/179051228971575.jpg" alt="C++ Code Review Master" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master" class="overflowclass">C++ Code Review Master</a>
<p class="overflowclass">组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。</p>
</div>
<a rel="nofollow" href="/xiazai/skill5502" title="C++ Code Review Master" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<pre class="brush:php;toolbar:false;">struct Node {
std::shared_ptr<node> parent;
std::shared_ptr<node> child;
};</node></node>
改成:
struct Node {
std::shared_ptr<node> parent; // 父持有子:shared_ptr
std::weak_ptr<node> child; // 子持有父:weak_ptr(避免循环)
};</node></node>
- 子访问父时必须用
child.lock(),且要检查是否为空 - 注意:不能只把
parent改成weak_ptr—— 那样父节点可能被提前释放,导致悬空 - 谁“拥有”谁,决定了哪边用
shared_ptr;weak_ptr只用于非拥有关系
weak_ptr 构造和赋值的限制
weak_ptr 不能直接从裸指针或 unique_ptr 构造,只能从 shared_ptr 或另一个 weak_ptr 初始化。
- 合法:
std::weak_ptr<int> wp(sp);</int>、std::weak_ptr<int> wp2(wp);</int> - 非法:
std::weak_ptr<int> wp(new int(1));</int>(编译错误) - 非法:
std::weak_ptr<int> wp(std::move(up));</int>(unique_ptr无法转weak_ptr) - 也不能用
reset()——weak_ptr没有这个成员函数
判断对象是否已被释放的两种方式
常用的是 lock() 后判空,但有时只需要知道“是否还活着”,不想获取所有权,这时用 expired() 更轻量:
if (wp.expired()) {
// 对象已销毁,无需 lock
} else {
auto p = wp.lock(); // 此时 lock() 几乎无开销
}
-
expired()内部只检查引用计数是否为 0,比lock()少一次原子增操作 - 但
expired()和后续lock()之间仍有竞态窗口,所以多数情况下直接lock()更稳妥 - 多线程环境下,
expired()返回false并不能保证lock()一定成功
真正容易被忽略的是:weak_ptr 的生命周期本身不依赖所指对象,它自己可以一直存在,哪怕目标早已销毁——这时候它就变成一个“空观察者”,不会崩溃,但也不再有意义。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










