为何在观察者线程中使用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的原因如下:
对象永远无法被销毁,导致内存泄漏
当你把shared_ptr传入线程并捕获到lambda里时,线程会持有这个shared_ptr的副本,此时对象的引用计数至少是2(假设主线程还有一个shared_ptr指向它)。即使主线程释放了自己的shared_ptr,线程里的副本还在持有,引用计数会保持为1,永远不会降到你判断的“等于1”的情况。这意味着对象永远不会被销毁,线程会无限循环跑下去,造成内存泄漏和资源浪费。use_count()的判断完全不可靠- 多线程环境下,
use_count()的返回值是瞬间的快照,在你判断use_count() > 1之后,其他线程可能立刻修改引用计数(比如另一个观察者释放了持有的shared_ptr),导致后续访问*sp时对象已经被销毁,触发未定义行为。 - C++标准并没有保证
use_count()的精确性(虽然大多数实现会返回准确值),依赖它做逻辑判断是糟糕的编程实践。
- 多线程环境下,
weak_ptr的语义完全匹配观察者场景
观察者的职责是观察对象状态,而非拥有对象。weak_ptr的设计初衷就是表达这种“非拥有式的引用”:它不会增加对象的引用计数,不会延长对象的生命周期,只有在需要访问对象时才通过lock()获取临时的shared_ptr来保证对象存活。这种语义既符合观察者的角色定位,又能安全检测对象是否已销毁。
内容的提问来源于stack exchange,提问作者Liviu Dorobantu
相关产品推荐
相关产品推荐

