C++ 的 weak_ptr 是个好东西,但也是个容易让人在细节上栽跟头的工具。它不持有引用计数,所以不能像普通指针那样直接解引用,必须通过 lock() 先拿到 shared_ptr 才能安全操作。这个机制背后的逻辑是什么,又该怎么用好它,咱们来拆开聊聊。

weak_ptr 为什么不能直接访问对象

原因其实很简单:weak_ptr 本身不持有引用计数,它只是对 shared_ptr 所管理对象的一个“弱观察”。它没有重载 *-> 运算符,所以直接调用 get() 或者解引用,编译阶段就会报错。

正确的做法是调用 lock() 方法,它会返回一个 shared_ptr。如果原来的对象还在,这个 shared_ptr 就是有效的;如果对象已经被释放,返回的就是空 shared_ptr,判断一下 !ptr 就能知道。

在观察者模式中如何用 weak_ptr 避免循环引用

观察者模式是循环引用的经典温床。典型场景是 Subject 持有一堆 shared_ptr,而 Observer 又持有一个指向 Subject 的 shared_ptr。这样一来,两者互相强引用,析构函数永远别想被调用。

解决办法很简单:Observer 改用 weak_ptr 来存储对 Subject 的引用。这样 Observer 不会增加 Subject 的引用计数,Subject 销毁后 Observer 仍然可以安全存在,只是下次调用 lock() 时会失败。

weak_ptr::lock() 和 expired() 的行为差异

expired() 是一个轻量级的检查,只读取控制块中的引用计数,不加锁也不增加计数,所以速度很快。lock() 则要原子地尝试将弱引用提升为强引用,开销略高,而且有可能失败。

weak_ptr 无法解决所有循环引用,注意原始指针陷阱

有人会试图用裸指针 Subject* 来替代 weak_ptr,觉得“我手动保证不 dangling 就行”。但在多线程、异步回调、延迟执行这些场景下,你根本没法确定 Subject 的生命周期边界,这种做法极其危险。

真正容易被忽略的点是:weak_ptr 必须由同一个 shared_ptr 初始化而来,跨实例赋值或从不同源头构造,会让观察彻底失效。

本文转载于:https://www.php.cn/faq/2313749.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。