weak_ptr需单独维护弱引用计数,因其不参与对象生命周期管理但需与shared_ptr共享控制块;控制块含shared_count、weak_count(初值为1)和ptr;lock()原子检查并递增shared_count以安全升级;shared_ptr析构时先减shared_count,若归零则销毁对象,再减weak_count,仅当二者同为0才释放控制块。

weak_ptr 的引用计数为什么需要单独维护
因为 weak_ptr 不能决定对象生死,它必须和 shared_ptr 共享同一个控制块(control block),但又不能影响 shared_ptr 的引用计数。所以得额外维护一个「弱引用计数」——记录还有多少 weak_ptr 指向该控制块,等所有 shared_ptr 和 weak_ptr 都销毁后,控制块本身才能释放。
控制块里要存哪几个关键字段
一个最小可行的控制块至少得有三个整型成员:
-
shared_count:当前有效的shared_ptr数量(也叫强引用计数) -
weak_count:当前有效的weak_ptr数量(不含自身,即控制块自己也算一次弱持有) -
ptr:指向托管对象的原始指针(T*)
注意:weak_count 初始值是 1,因为控制块自己“持有一份弱引用”——它得确保自己不被提前释放;每次构造 weak_ptr 时 weak_count 加 1,析构时减 1;只有当 shared_count == 0 && weak_count == 0 时,才 delete 控制块和托管对象。
weak_ptr::lock() 怎么安全地升级为 shared_ptr
核心逻辑是原子地检查 shared_count > 0,如果成立,就将 shared_count 加 1,并返回新的 shared_ptr。失败则返回空 shared_ptr。
立即学习“C++免费学习笔记(深入)”;
示例关键片段:
shared_ptr<T> lock() const {
if (control_block && control_block->shared_count.load() > 0) {
// 原子递增,避免竞态
control_block->shared_count.fetch_add(1, std::memory_order_relaxed);
return shared_ptr<T>(control_block->ptr, control_block);
}
return shared_ptr<T>();
}
这里容易踩坑:不能只读 shared_count 就构造,必须原子递增,否则可能多个 weak_ptr::lock() 同时通过判断,却只有一份实际对象存活,导致重复析构。
shared_ptr 析构时如何触发 weak_count 降级
shared_ptr 析构时,先对 shared_count 减 1;若减完为 0,说明对象该销毁了,此时调用 delete ptr,但控制块还不能删——得等 weak_count 也归零。
所以析构逻辑里要有:
- 递减
shared_count - 若
shared_count == 0,执行delete ptr - 无论如何,都要递减
weak_count(因为控制块本身那份弱引用还在) - 最后检查
shared_count == 0 && weak_count == 0,满足则delete control_block
最容易忽略的是:即使 shared_ptr 是最后一个强引用,也不能立刻 delete 控制块——因为可能还有 weak_ptr 活着,它们需要访问控制块里的 shared_count 来做 lock() 判断。


















