既然有shared_ptr的use_count(),为何还需要weak_ptr?
你的疑问很典型,先看你给出的示例代码:
#include <memory> #include <cassert> using namespace std; int main() { shared_ptr<int> a(new int(10)); weak_ptr<int> wa(a); a.reset(); assert(a.use_count() == 0); // clause 1 - good. indicate no binding objects assert(wa.lock() == nullptr); // clause 2 - good. same as above return 0; }
在这个单shared_ptr的场景下,两者结果确实一致,但这只是特殊情况,实际开发中weak_ptr的不可替代性体现在以下核心场景:
1. 你没有持有对象的shared_ptr时,只能靠weak_ptr监控存活
很多时候你只是对象的观察者,不想持有对象(避免延长对象生命周期,比如缓存、观察者模式)。这时候你手里根本没有对应的shared_ptr,自然无法调用它的use_count()。
比如缓存系统:缓存中存储weak_ptr指向业务对象,当需要使用时通过lock()检查对象是否还存活——如果用shared_ptr存缓存,会导致对象永远无法被销毁,完全失去缓存的意义。
2. shared_ptr的use_count()无法准确反映对象的存活状态
当你手里的shared_ptr不是对象的唯一持有者时,use_count()的结果会误导你。举个例子:
shared_ptr<int> a(new int(10)); shared_ptr<int> b = a; // 此时对象的引用计数是2 weak_ptr<int> wa(a); a.reset(); // a和对象解绑,a的use_count()变为0 // 但对象还被b持有,根本没被销毁 assert(a.use_count() == 0); // 这个判断只能说明a自己没有其他拷贝,和对象存活无关 assert(wa.lock() != nullptr); // 正确反映对象还活着
这里a.use_count()返回0,但对象明明还存在——因为use_count()的语义是当前shared_ptr实例对应的引用计数,而非对象的存活状态。当shared_ptr被reset后,它已经和对象的控制块解绑,此时的use_count()完全无法代表对象是否还活着。
3. weak_ptr绑定到对象的控制块,而非单个shared_ptr
weak_ptr从一开始就绑定到对象的控制块,它的lock()方法直接查询控制块中对象是否还存在;而shared_ptr的use_count()只是当前实例的引用计数,和对象的整体存活状态没有直接关联。
总结:你的示例是极端场景(只有一个shared_ptr持有对象),但在绝大多数实际场景中,要么你没有持有shared_ptr,要么手里的shared_ptr不是唯一持有者,这时候weak_ptr才是检测对象存活状态的正确方式。
内容的提问来源于stack exchange,提问作者yapkm01

