关于C++标准库weak_ptr的lock()方法设计疑问
关于C++ weak_ptr的设计疑问及解析
我正在学习C++11/14/17的相关概念,了解到了weak_ptr的用法。以下是我实现的无bug示例代码:
#include <iostream> using namespace std; class Printer { weak_ptr<int> m_Value{}; public: void SetValue(weak_ptr<int> p) { m_Value = p; } void Print() const { cout << "ref count = " << m_Value.use_count() << endl; if (m_Value.expired()) { cout << "resource expired"; return; } auto sp = m_Value.lock(); cout << "sp ref count = " << sp.use_count() << endl; cout << "Value is = " << *sp << endl; } }; int main() { Printer prn; int num; cout << "Enter num = "; cin >> num; shared_ptr<int> p{new int(num)}; prn.SetValue(p); if (*p > 10) { p = nullptr; } prn.Print(); }
我的疑问
为何weak_ptr需要由程序员手动调用lock()方法来获取shared_ptr并增加引用计数,而非在设计中自动完成此操作?存在哪些无需增加引用计数的场景?
解析
一、手动调用lock()的核心原因
weak_ptr的本质是不拥有对象所有权的观察者,它的设计目标就是避免循环引用,同时允许安全地检查对象是否存活。如果自动获取shared_ptr并增加引用计数,就违背了它的核心定位:
- 打破循环引用的基础:如果
weak_ptr自动提升为shared_ptr,两个互相持有对方weak_ptr的对象,在访问时会自动增加引用计数,最终还是会形成无法释放的循环,完全失去weak_ptr解决循环引用的意义。 - 控制权交给开发者:对象的存活周期应该由业务逻辑决定,而非智能指针自动干预。手动调用
lock()让开发者明确知道自己正在延长对象的生命周期,避免无意识地阻止对象被销毁。 - 线程安全与状态一致性:
expired()检查和lock()不是原子操作,但lock()本身是线程安全的。如果自动完成提升,开发者无法处理“检查时对象存活,但实际访问时对象已被销毁”的竞态条件,手动调用lock()后再访问,能保证在shared_ptr的生命周期内对象一定存活。
二、无需增加引用计数的场景
- 仅检查对象是否存活:比如定期监控某个资源的状态,只需要调用
expired()判断对象是否还存在,不需要访问对象内容,此时完全没必要提升为shared_ptr,避免不必要的引用计数变化。 - 临时判断后无需持续访问:比如在某些分支逻辑中,先确认对象存活再执行后续操作,但后续操作不需要持有对象所有权,这种情况下只需要
expired()做判断,不需要提升。 - 避免不必要的资源占用:如果对象本身占用大量资源,仅仅为了检查状态就提升
shared_ptr,会导致对象无法及时被销毁,浪费系统资源。
内容的提问来源于stack exchange,提问作者amutamil
相关产品推荐
相关产品推荐

