You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何在观察者线程中使用weak_ptr?能否用shared_ptr替代?

为什么在观察者线程场景中必须用weak_ptr而非shared_ptr?

我看到一个用weak_ptr实现观察者线程的示例代码:

std::thread observer;

void observe(std::weak_ptr<int> wp) {
 //Start observer thread
 observer = std::thread([wp](){
  while(true) {
   std::this_thread::sleep_for(std::chrono::seconds(1));

   //Try acquiring a shared_ptr from weak_ptr
   if(std::shared_ptr<int> p = wp.lock()) {
    //Success
    std::cout << "Observing: " << *p << "\n";
   } else {
    //The managed object is destroyed. 
    std::cout << "Stop\n";
    break;
   }
  }
 });
}

但我觉得可以改用shared_ptr实现,代码如下:

void observe(std::shared_ptr<int> sp) {
 observer = std::thread([sp](){
  while(true) {
   std::this_thread::sleep_for(std::chrono::seconds(1));

   if(sp.use_count() > 1) {
    //Success
    std::cout << "Observing: " << *sp << "\n";
   } else {
    //The managed object is about to be destroyed. 
    std::cout << "Stop\n";
    break;
   }
  }
 });
}

我的想法是:当shared_ptr的use_count大于1时继续观测,等于1时停止,此时动态对象会在函数返回后被销毁。想请教这个场景下使用weak_ptr的必要性。


你的方案存在核心问题,必须用weak_ptr的原因如下:

  1. 对象永远无法被销毁,导致内存泄漏
    当你把shared_ptr传入线程并捕获到lambda里时,线程会持有这个shared_ptr的副本,此时对象的引用计数至少是2(假设主线程还有一个shared_ptr指向它)。即使主线程释放了自己的shared_ptr,线程里的副本还在持有,引用计数会保持为1,永远不会降到你判断的“等于1”的情况。这意味着对象永远不会被销毁,线程会无限循环跑下去,造成内存泄漏和资源浪费。

  2. use_count()的判断完全不可靠

    • 多线程环境下,use_count()的返回值是瞬间的快照,在你判断use_count() > 1之后,其他线程可能立刻修改引用计数(比如另一个观察者释放了持有的shared_ptr),导致后续访问*sp时对象已经被销毁,触发未定义行为。
    • C++标准并没有保证use_count()的精确性(虽然大多数实现会返回准确值),依赖它做逻辑判断是糟糕的编程实践。
  3. weak_ptr的语义完全匹配观察者场景
    观察者的职责是观察对象状态,而非拥有对象。weak_ptr的设计初衷就是表达这种“非拥有式的引用”:它不会增加对象的引用计数,不会延长对象的生命周期,只有在需要访问对象时才通过lock()获取临时的shared_ptr来保证对象存活。这种语义既符合观察者的角色定位,又能安全检测对象是否已销毁。


内容的提问来源于stack exchange,提问作者Liviu Dorobantu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 23:30:49