我应该通过引用传递shared_ptr吗?

Ben*_*rst 96 c++ shared-ptr

传递shared_ptr的最佳做法是什么?

目前我传递shared_ptr函数参数,如下所示:

void function1( shared_ptr<TYPE>& value );
Run Code Online (Sandbox Code Playgroud)

Ker*_* SB 101

在受控环境中,您可以通过常量引用传递共享指针.确保没有人同时删除该对象,但如果你小心对谁提供引用,这不应该太难.

通常,您应该将共享指针作为直接副本传递.这给了它预期的语义:每个包含共享指针副本的作用域凭借其在所有权中的"共享"来保持对象的活动.

不总是通过值传递的唯一原因是复制共享指针由于原子引用计数更新而以一定的价格出现; 但是,这可能不是一个主要问题.


可选的题外话:

由于主要问题已得到解答,或许考虑一些永远不应使用共享指针的方法是有益的.这是一个小小的思想实验.让我们定义一个共享指针类型SF = std::shared_ptr<Foo>.为了考虑引用,而不是传递函数参数让我们看一下类型RSF = std::reference_wrapper<T>.也就是说,如果我们有一个共享指针SF p(std::make_shared<Foo>());,那么我们可以使用值语义来创建一个引用包装器RSF w = std::ref(p);.这么多设置.

现在,每个人都知道指针的容器是雷区.因此std::vector<Foo*>,维护是一场噩梦,并且由于不正确的终身管理而产生任何数量的错误.从概念上讲,更糟糕的是,谁拥有容器存储指针的对象永远都不清楚.指针甚至可以是指向动态对象,自动对象和垃圾的指针.没有人能说出来.所以标准解决方案是使用std::vector<SF>.这是使用共享指针的正确方法.另一方面,你绝对不能使用的是std::vector<RSF>- 这是一个无法控制的怪物,它实际上与裸指针的原始矢量非常相似!例如,不清楚您持有引用的对象是否仍然存在.参考共享指针已经打败了它的整个目的.

对于第二个示例,假设我们SF p像以前一样拥有共享指针.现在我们有一个int foo(SF)我们想要并发运行的函数.通常的std::thread(foo, p)工作正常,因为线程构造函数会复制其参数.但是,如果我们说过std::thread(foo, std::ref(p)),我们会遇到各种各样的麻烦:调用范围中的共享指针可能会过期并销毁对象,并且您将留下悬空引用和无效指针!

我希望这两个公认的相当人为的例子能够让你明白当你真的希望你的共享指针被副本传递时.在一个设计良好的程序中,应该始终清楚谁负责哪些资源,并且当正确使用时,共享指针是一个很好的工具.

  • @wolfgang:稍微不那么神奇:如果你不信任被叫者*不*存储对你指针的引用,那么总是传递一个值,因为那样说,"在这里,你承担责任".通过const-reference传递就像"请为我保留一分钟",如果你认为它们可能会丢弃它,那就不要了. (2认同)

jal*_*alf 27

这取决于你想要什么.被叫方应该共享对象的所有权吗?然后它需要自己的副本shared_ptr.所以按价值传递它.

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

C++中的最佳实践始终是为对象明确定义所有权语义.没有普遍的"总是这样做"来取代实际的思想.

如果你总是按值传递共享指针,那么代价很高(因为复制它们比原始指针要贵得多).如果你从未这样做过,那么首先使用共享指针是没有意义的.

当新函数或对象需要共享指针对象的所有权时,复制共享指针.

  • 你可以复制`void store(shared_ptr <T> const&sharedRef){this-> mySharedRef = shredRef;}`.如果shredRef将通过值传递,它将递增计数器两次.当然你可以做`void store(shared_ptr <T> sharedRef){shredRef.swap(this-> mySharedRef);}`来做同样的事情. (3认同)

Kat*_*ory 8

如果通过引用传递,则通过const引用传递它.这表明你出于性能原因通过了ref.此外,尽可能使用make_shared,因为它保存了间接,因此提供了性能提升.

  • `make_shared` 总是一件好事,但请注意,它仅在创建第一个共享指针时起作用。 (2认同)

归档时间:

查看次数:

75687 次

最近记录:

13 年,9 月 前