通过使用
const&
传递
shared_ptr
的好处在于不需要增加和减少引用计数。由于这些操作必须是线程安全的,因此可能会很昂贵。
你说得很对,确实存在一个风险,即可能存在一系列通过引用传递的链,后来使链的头部失效。我曾经在一个真实项目中遇到过这种情况,并产生了真实的后果。一个函数在容器中找到了一个
shared_ptr
,然后将其引用传递到调用栈中。调用栈深处的一个函数从容器中删除了对象,导致所有引用突然指向一个不存在的对象。
因此,当你通过引用传递东西时,调用者必须确保它在函数调用的生命周期内存活。如果这是一个问题,请不要使用引用传递。
(我假设您有一个使用
shared_ptr
而不是引用传递的特定原因的用例。最常见的原因是被调用的函数可能需要延长对象的生命周期。)
更新:对于那些感兴趣的人,以下是关于这个 bug 的更多细节:该程序具有共享对象并实现内部线程安全的功能。它们保存在容器中,函数通常会延长它们的生命周期。
这种特定类型的对象可以存在于两个容器中。一个用于活动对象,另一个用于非活动对象。一些操作在活动对象上工作,一些在非活动对象上工作。错误情况发生在对非活动对象收到命令时,该命令使其变为活动状态,而唯一的
shared_ptr
对象由非活动对象的容器持有。
该非活动对象位于其容器中。将指向容器中的shared_ptr
的引用通过引用传递给命令处理程序。通过一系列引用,这个shared_ptr
最终到达了意识到这是一个需要激活的非活动对象的代码。该对象被从非活动容器中删除(这会销毁非活动容器的shared_ptr
),并添加到活动容器中(这会向“添加”例程传递的shared_ptr
添加另一个引用)。
此时,唯一存在的指向对象的shared_ptr
可能是在非活动容器中的那个。调用栈中的每个其他函数只是对它的引用。当对象从非活动容器中删除时,对象可以被销毁,所有这些引用都指向一个不再存在的shared_ptr
。
解决这个问题大约花了一个月的时间。
std::shared_ptr
上执行操作还是只需要对指向的对象进行操作?如果是后者,那么就使用const T&
;doSomething
函数不需要关心对象是如何存储的。 - TartanLlamashared_ptr
的原因是您有一个使用案例,您希望需要扩展生命周期。 - David Schwartz