关于c ++:我应该通过引用传递shared_ptr吗?

Should I pass a shared_ptr by reference?

本问题已经有最佳答案,请猛点这里访问。

传递shared_ptr的最佳实践是什么?

目前,我像这样传递shared_ptr函数参数:

1
void function1( shared_ptr<TYPE>& value );


在受控情况下,可以通过常量引用传递共享指针。确保没有人同时删除该对象,尽管如果您要小心向谁提供引用,这应该不太困难。

通常,您应该将共享指针作为直接副本传递。这赋予了它预期的语义:每个包含共享指针副本的范围都通过对象在所有权中的"共享"使对象保持活动状态。

不总是按值传递的唯一原因是,由于原子引用计数的更新,复制共享指针要付出一定的代价。但是,这可能不是主要问题。

可选题外话:

既然已经回答了主要问题,那么考虑一些永远不应该使用共享指针的方法也许是有益的。这是一个小小的思想实验。让我们定义一个共享指针类型SF = std::shared_ptr。为了考虑引用,而不是传递函数参数,让我们看一下类型RSF = std::reference_wrapper< T >。也就是说,如果我们有一个共享的指针SF p(std::make_shared());,那么我们可以通过RSF w = std::ref(p);使用值语义创建一个引用包装。设置非常重要。

现在,每个人都知道指针容器是雷区。因此std::vector将是维护的噩梦,并且任何不正确的生命周期管理都会引起许多错误。从概念上讲,更糟的是,永远不清楚谁拥有容器存储其指针的对象。指针甚至可以是指向动态对象,自动对象和垃圾的指针的混合。没有人能告诉。因此,标准解决方案是改用std::vector。这是使用共享指针的正确方法。另一方面,您永远不能使用的是std::vector-这是一个难以处理的怪物,实际上与裸指针的原始向量非常相似!例如,尚不清楚您持有引用的对象是否仍然存在。引用共享指针已经破坏了它的全部目的。

对于第二个示例,假设我们像以前一样有一个共享指针SF p。现在,我们有一个要同时运行的函数int foo(SF)。通常的std::thread(foo, p)效果很好,因为线程构造函数会复制其参数。但是,如果我们说std::thread(foo, std::ref(p)),就会遇到各种各样的麻烦:调用范围中的共享指针可能到期并破坏该对象,并且您将剩下一个悬挂的引用和一个无效的指针!

我希望当您确实希望共享指针通过副本传递时,这两个公认的相当人为的示例能为您提供一些启示。在一个设计良好的程序中,应始终清楚由谁负责哪些资源,并且在正确使用时,共享指针是完成工作的好工具。


那取决于你想要什么。被调用者是否应该共享对象的所有权?然后,它需要自己的shared_ptr副本。因此,将其传递给价值。

如果函数仅需要访问调用者拥有的对象,则继续并传递(const)引用,以避免复制shared_ptr的开销。

C ++的最佳实践始终是为对象明确定义所有权语义。没有通用的"总是这样做"来代替实际思想。

如果您总是按值传递共享指针,那么它将变得很昂贵(因为复制它们比原始指针要昂贵得多)。如果您从不这样做,那么首先使用共享指针是没有意义的。

当新功能或对象需要共享指针的所有权时,请复制共享指针。


如果通过引用传递,则通过const引用传递。这清楚地表明,出于性能原因,您正在通过ref。另外,请尽可能使用make_shared,因为它可以保存间接寻址,从而提高性能。