以值传递或常量引用传递 std::shared_ptr 并将其存储在容器中?

7

考虑以下向量:

std::vector<std::shared_ptr<X>> myVector;

以下是两个将给定元素添加到向量中的函数:

void foo1(std::shared_ptr<X> x)
{
    myVector.push_back(x);
}

void foo2(const std::shared_ptr<X>& x)
{
    myVector.push_back(x);
}

我的理解是,两个函数都将一个shared_ptr推入到X的向量中,从而增加了X的引用计数。第一个函数导致引用计数多增加和减少一次,但这是不必要的。

我的理解正确吗?因此第二个选项更可取吗?


3
由于你是按值传递,所以会调用复制构造函数。因此,你的理解是正确的。 - 101010
2
可能是shared_ptr按引用还是按值传递?的重复问题。 - eerorika
复制实际上可以省略。 - Edward Strange
@101010 在第一个例子中是按值传递,对吧? - ksl
@ksl 在 foo1 中。 - 101010
@101010 如果您将回复作为答案提交,我会很高兴接受它。 - ksl
3个回答

5
在函数foo1中,你通过值传递参数(即共享指针)。因此,std::shared_ptr<X>的复制构造函数将被调用(即引用计数将增加,并在foo1}处被调用本地副本的析构函数时减少)。
在函数foo2中,你通过const引用传递参数(即共享指针)。因此,你传递了原始对象的const限定别名(即引用计数不会增加)。
你也可以在以下示例中看到这一点:
struct X {};

void foo1(std::shared_ptr<X> x) { 
  std::cout << "count in foo1(): " << x.use_count() << std::endl;
}

void foo2(const std::shared_ptr<X>& x) {
  std::cout << "count in foo2(): " << x.use_count() << std::endl;
}

int main() {
  std::shared_ptr<X> x(new X);
  std::cout << "count in main(): " << x.use_count() << std::endl;
  foo1(x);
  foo2(x);
}

输出:

count in main(): 1
count in foo1(): 2
count in foo2(): 1

如您在foo1中所见,不同的shared_ptr实例数量为2。这包括在main定义的原始shared_ptr和在foo1中的副本。而在foo2中,引用计数仍然为1。

因此,您的推理是正确的。


你什么情况下不会使用选项2? - ksl
1
基本上,大部分时间我会使用选项2。只有在函数的某个时刻我想要复制的共享指针指向其他地方时,才会使用选项1。 - 101010

3
您应该将函数重写为:
void foo1(std::shared_ptr<X> x)
{
    myVector.emplace_back(std::move(x));
}

void foo2(const std::shared_ptr<X>& x)
{
    myVector.emplace_back(x);
}

那么两个版本都应该更有效率,具体哪个更有效率取决于情况和特定的编译器,如果有差异,则很可能非常小。


甚至可以使用 void foo1(std::shared_ptr<X> &&x) - Thomas Sparber
3
在这种情况下,emplace_back 不会比 push_back 更加高效。 - Simple

1
通常最好通过引用传递共享指针,因为原子增量往往会降低性能。在您的情况下,这不会引起注意,因为您之后仍然会复制它。

只有 foo1 的副本,是吗? - ksl
@ksl 你认为 foo2 在内部做了什么?你认为它是相当于 new_vector_slot = x; 还是相当于 new_vector_slot = std::shared_ptr<X>(x); - David Schwartz
@DavidSchwartz 后者。 - ksl
@ksl 然后 foo2 也会复制。 - David Schwartz
@ksl 你说过只有 foo1 会复制,同时你认为 foo2 的实现方式必然会复制。这两件事情不可能同时成立。 - David Schwartz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接