当应用程序中涉及智能指针时,我已经阅读了很多关于性能问题的讨论。常见的建议之一是将智能指针作为 const& 而不是副本传递,如下所示:
void doSomething(std::shared_ptr<T> o) {}
相对
void doSomething(const std::shared_ptr<T> &o) {}
但是,第二个变体实际上不是破坏了共享指针的目的吗?我们实际上在这里共享共享指针,因此如果由于某些原因指针在调用代码中被释放(考虑可重入性或副作用),则 const 指针将变为无效。共享指针实际上应该防止的情况。我知道 const& 节省了一些时间,因为不涉及复制,也没有锁定来管理引用计数。但代价是让代码不那么安全,对吧?
原文由 Mike Lischke 发布,翻译遵循 CC BY-SA 4.0 许可协议
通过
const&
传递shared_ptr
的优点是引用计数不必先增加再减少。因为这些操作必须是线程安全的,所以它们可能很昂贵。你是对的,你可能有一个通过引用传递链的风险,这以后会使链的头部无效。这曾经发生在我的一个真实世界项目中,具有真实世界的后果。一个函数在容器中找到了一个
shared_ptr
并将对它的引用传递给调用堆栈。调用堆栈深处的一个函数从容器中删除了对象,导致所有引用突然引用了一个不再存在的对象。因此,当您通过引用传递某些内容时,调用者必须确保它在函数调用的整个生命周期内都存在。如果这是一个问题,请不要使用引用传递。
(我假设您有一个用例,其中有一些特定的原因需要通过
shared_ptr
而不是通过引用。最常见的原因是调用的函数可能需要延长对象的寿命.)_更新_:对于那些感兴趣的人,有关该错误的更多详细信息:该程序具有共享并实现内部线程安全的对象。它们被装在容器中,延长它们的使用寿命的功能很常见。
这种特殊类型的对象可以存在于两个容器中。一个是活动的,一个是不活动的。一些操作对活动对象起作用,一些对非活动对象起作用。当在非活动对象上接收到使其处于活动状态的命令时发生错误情况,而该对象的唯一
shared_ptr
由非活动对象的容器保存。非活动对象位于其容器中。通过引用将容器中对
shared_ptr
的引用传递给命令处理程序。通过一连串的引用,这个shared_ptr
最终到达了意识到这是一个必须激活的非活动对象的代码。该对象已从非活动容器中移除(这破坏了非活动容器的shared_ptr
)并添加到活动容器中(这添加了对传递给“添加”例程的shared_ptr
的另一个引用) .此时,存在的对象的唯一
shared_ptr
可能是非活动容器中的那个。调用堆栈中的每个其他函数都只是对它的引用。当对象从非活动容器中移除时,对象可能会被销毁,并且所有这些引用都指向一个不再存在的shared_ptr
。花了大约一个月的时间来解决这个问题。