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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/8385457/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 18:29:19  来源:igfitidea点击:

Should I pass a shared_ptr by reference?

c++shared-ptr

提问by Ben Crowhurst

What are the best practices for passing a shared_ptr?

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

Currently I pass shared_ptr function arguments like so:

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

void function1( shared_ptr<TYPE>& value );

回答by Kerrek SB

In controlled circumstances you can pass the shared pointer by constant reference. Be sure that nobody is concurrently deleting the object, though this shouldn't be too hard if you're careful about to whom you give references.

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

In general, you should pass the shared pointer as a straight copy. This gives it its intended semantics: Every scope that contains a copy of the shared pointer keeps the object alive by virtue of its "share" in the ownership.

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

The only reason not to always pass by value is that copying a shared pointer comes at a certain price on account of the atomic reference count update; however, this might not be a major concern.

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



Optional digression:

可选题外话:

Since the main question has been answered, perhaps it is instructive to consider a few ways in which you should neveruse a shared pointer. Here is a little thought experiment. Let us define a shared pointer type SF = std::shared_ptr<Foo>. In order to consider references, rather than passing function arguments let us look at the type RSF = std::reference_wrapper<T>. That is, if we have a shared pointer SF p(std::make_shared<Foo>());, then we can make a reference wrapper with value semantics via RSF w = std::ref(p);. So much for the setup.

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

Now, everybody knows that containers of pointers are minefield. So std::vector<Foo*>will be a nightmare to maintain, and any number of bugs arise from improper lifetime management. What's worse conceptually is that it is never clear who ownsthe objects whose pointers the container stores. The pointers could even be a mix of pointers to dynamic objects, automatic objects, and garbage. Nobody can tell. So the standard solution is to use std::vector<SF>instead. This is The Right Way to use the shared pointer. On the other hand, what you must never use is std::vector<RSF>-- this is an unmanageable monster that is actually very similar to the original vector of naked pointers! For example, it's not clear whether the object to which you hold a reference is still alive. Taking a reference of the shared pointer has defeated its entire purpose.

现在,每个人都知道指针的容器是雷区。因此std::vector<Foo*>,维护将是一场噩梦,并且不正确的生命周期管理会导致任何数量的错误。在概念上更糟糕的是,永远不清楚谁拥有容器存储其指针的对象。指针甚至可以是指向动态对象、自动对象和垃圾的指针的混合。谁也说不清。所以标准的解决方案是使用std::vector<SF>。这是使用共享指针的正确方法。另一方面,你绝对不能使用的是std::vector<RSF>——这是一个难以驾驭的怪物,其实和裸指针的原始向量非常相似!例如,不清楚您持有引用的对象是否还活着。引用共享指针已经违背了它的全部目的。

For a second example, suppose we have a shared pointer SF pas before. Now we have a function int foo(SF)that we want to run concurrently. The usual std::thread(foo, p)works just fine, since the thread constructor makes a copyof its arguments. However, had we said std::thread(foo, std::ref(p)), we'd be in all sorts of trouble: The shared pointer in the calling scope could expire and destroy the object, and you would be left with a dangling reference and an invalid pointer!

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

I hope these two admittedly fairly contrived examples shed a bit of light on when you really want your shared pointers to be passed around by copy. In a well-designed program, it should always be clear who is responsible for which resources, and when used right, the shared pointer is a great tool for the job.

我希望这两个公认的相当人为的示例能在您真正希望通过copy传递共享指针时对您有所启发。在一个设计良好的程序中,应该始终清楚谁负责哪些资源,如果使用得当,共享指针是完成这项工作的一个很好的工具。

回答by jalf

That depends on what you want. Should the callee share ownership of the object? Then it needs its own copy of the shared_ptr. So pass it by value.

这取决于你想要什么。被调用者应该共享对象的所有权吗?然后它需要自己的shared_ptr. 所以按值传递它。

If a function simply needs to access an object owned by the caller, go ahead and pass by (const) reference, to avoid the overhead of copying the shared_ptr.

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

The best practice in C++ is alwaysto have clearly defined ownership semantics for your objects. There is no universal "always do this" to replace actual thought.

C++ 中的最佳实践总是为您的对象明确定义所有权语义。没有普遍的“总是这样做”来代替实际的想法

If you alwayspass shared pointers by value, it gets costly (because they're a lot more expensive to copy than a raw pointer). If you neverdo it, then there's no point in using a shared pointer in the first place.

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

Copy the shared pointer when a new function or object needs to share ownership of the pointee.

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

回答by Kate Gregory

Pass it by const reference if you pass by reference. That makes it clear that you're passing by ref for performance reasons. Also, use make_shared when you can since it saves an indirection so gives a perf boost.

如果通过引用传递,则通过常量引用传递它。这清楚地表明您出于性能原因正在通过 ref 。此外,尽可能使用 make_shared,因为它节省了间接访问,因此可以提高性能。