std::weak_ptr通过替换循环中非主导方的std::shared_ptr来打破引用计数闭环,需明确所有权流向、访问时必用lock()判空、并将weak_ptr定位为结构断点。

原生智能指针(特指 std::shared_ptr)本身不解决循环引用——它正是循环引用的根源。所谓“通过弱指针解决”,本质是**人为设计策略:用 std::weak_ptr 替换循环中非主导的一方 shared_ptr,从而打破引用计数闭环**。看穿这个策略,关键不在语法细节,而在识别三类映射关系。
所有权流向决定 weak_ptr 放在哪一端
shared_ptr 表达的是“我负责你活着”;weak_ptr 表达的是“我需要你,但不拦着你死”。策略映射的第一层,就是明确谁拥有谁:
- 父节点创建并管理子节点生命周期 → 子节点用
weak_ptr<parent></parent>回指 - A 模块注册回调到 B 模块 → B 中保存对 A 的
weak_ptr,而非shared_ptr - 缓存容器持有对象 → 缓存项用
weak_ptr,避免阻止被缓存对象析构
访问模式决定 lock() 是否必须包裹每次使用
weak_ptr 不能直接解引用,lock() 不是可选操作,而是安全前提。策略映射的第二层,是把“访问”拆解为原子两步:
- 调用
lock()→ 原子检查对象是否存活 + 瞬时提升引用计数 - 判空后使用返回的
shared_ptr→ 确保整个使用期间对象不会被析构 - 绝不用
expired()预检再lock(),中间存在竞态窗口
结构闭环决定 weak_ptr 是破环点,不是装饰品
循环引用不是偶然 bug,而是数据结构固有闭环在引用计数模型下的必然表现。策略映射的第三层,是把 weak_ptr 定位为“结构断点”:
- 树形结构中,父子双向指针构成环 → 子节点的 parent 成员必须是
weak_ptr - 观察者模式中,Subject 持有 Observer 列表 → Observer 应持
weak_ptr<subject></subject>回调,而非反向强引用 - 两个协作类 A/B,A 显式构造 B 并长期持有 → B 对 A 的引用只能是
weak_ptr
真正看穿策略,就是意识到:weak_ptr 不是一种“更弱的指针”,而是一种显式的、带访问协议的所有权让渡声明。它不改变 shared_ptr 的行为,只修正人对所有权边界的误设。










