传递 const shared_ptr<T>& 而不是 shared_ptr<T> 作为参数

新手上路,请多包涵

当应用程序中涉及智能指针时,我已经阅读了很多关于性能问题的讨论。常见的建议之一是将智能指针作为 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 许可协议

阅读 1.1k
2 个回答

通过 const& 传递 shared_ptr 的优点是引用计数不必先增加再减少。因为这些操作必须是线程安全的,所以它们可能很昂贵。

你是对的,你可能有一个通过引用传递链的风险,这以后会使链的头部无效。这曾经发生在我的一个真实世界项目中,具有真实世界的后果。一个函数在容器中找到了一个 shared_ptr 并将对它的引用传递给调用堆栈。调用堆栈深处的一个函数从容器中删除了对象,导致所有引用突然引用了一个不再存在的对象。

因此,当您通过引用传递某些内容时,调用者必须确保它在函数调用的整个生命周期内都存在。如果这是一个问题,请不要使用引用传递。

(我假设您有一个用例,其中有一些特定的原因需要通过 shared_ptr 而不是通过引用。最常见的原因是调用的函数可能需要延长对象的寿命.)

_更新_:对于那些感兴趣的人,有关该错误的更多详细信息:该程序具有共享并实现内部线程安全的对象。它们被装在容器中,延长它们的使用寿命的功能很常见。

这种特殊类型的对象可以存在于两个容器中。一个是活动的,一个是不活动的。一些操作对活动对象起作用,一些对非活动对象起作用。当在非活动对象上接收到使其处于活动状态的命令时发生错误情况,而该对象的唯一 shared_ptr 由非活动对象的容器保存。

非活动对象位于其容器中。通过引用将容器中对 shared_ptr 的引用传递给命令处理程序。通过一连串的引用,这个 shared_ptr 最终到达了意识到这是一个必须激活的非活动对象的代码。该对象已从非活动容器中移除(这破坏了非活动容器的 shared_ptr )并添加到活动容器中(这添加了对传递给“添加”例程的 shared_ptr 的另一个引用) .

此时,存在的对象的唯一 shared_ptr 可能是非活动容器中的那个。调用堆栈中的每个其他函数都只是对它的引用。当对象从非活动容器中移除时,对象可能会被销毁,并且所有这些引用都指向一个不再存在的 shared_ptr

花了大约一个月的时间来解决这个问题。

原文由 David Schwartz 发布,翻译遵循 CC BY-SA 3.0 许可协议

我认为通过 const & 如果目标函数是同步的并且仅在执行期间使用该参数并且在返回时不再需要它,则它是完全合理的。在这里节省增加引用计数的成本是合理的——因为在这些有限的情况下你并不需要额外的安全性——只要你了解其中的含义并确定代码是安全的。

这与函数需要保存参数(例如在类成员中)以供以后重新引用时相反。

原文由 Smeeheey 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题