C++中是否可以保存shared_ptr所管理对象的引用?有何风险?
核心风险说明
你写的这段代码在当前main函数的执行流程里不会有任何运行问题,但存在完全无感知的悬空引用隐患,没有任何编译期保护机制帮你拦截错误。
问题本质
你在parentObj里存的thing裸引用,和被引用对象的生命周期没有任何绑定关系:
- 当前代码里两个
shared_ptr的作用域完全重合,析构顺序是先销毁theObj、再销毁thingInstance,引用从头到尾都有有效值,自然不会出问题。 - 但只要后续代码里
thingInstance提前被销毁(比如主动reset、被移动走、提前跳出作用域),parentObj里存的isThisOK就会立刻变成悬空引用,后续访问就是未定义行为。这种bug编译器不会报错,运行时可能偶发崩溃、读到脏值,排查成本非常高。
举个最容易复现的错误场景:在main函数里完成两个对象的创建后,加一句thingInstance.reset();,再去读theObj->isThisOK.blah,程序直接就炸了——而你存引用的写法,从代码表面根本看不出来这里存在隐式的生命周期依赖约束。
不同场景的选型建议
关于要不要换成weak_ptr,完全要看你业务上对两个对象的所有权定义,不要机械套模板:
- 如果业务逻辑里
parentObj正常运行必须依赖有效的thing对象,那直接让parentObj持有shared_ptr<thing>是最稳妥的选择——直接把thing的生命周期和parentObj绑定为共享关系,根上避免悬空,这种场景用weak_ptr反而会让你每次访问都要加判空,平白增加代码复杂度。 - 如果业务逻辑里
parentObj和thing是平行关系,允许thing先被销毁,且parentObj在thing销毁后要能感知到依赖失效,这时候才适合用weak_ptr:每次需要访问thing的时候先调用lock()拿到临时的shared_ptr,拿到就正常用,拿不到就走对象已销毁的分支处理。 - 如果你能100%保证thing的生命周期一定长于parentObj(比如二者都是同一个顶层对象的成员,生命周期完全一致),那存裸引用是完全合理的选择,没必要为了“显得用了智能指针”增加额外开销。
你当前代码的核心问题不是存引用不对,是两个独立的shared_ptr完全没有生命周期关联,才给悬空留了口子。
内容的提问来源于stack exchange,提问作者deltav
相关产品推荐
相关产品推荐

