通过value或const ref传递std :: shared_ptr然后存储在容器中?

时间:2015-11-05 15:45:33

标签: c++ shared-ptr pass-by-value reference-counting pass-by-const-reference

考虑以下向量:

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 个答案:

答案 0 :(得分: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);
}

然后两个版本应该更高效,哪个版本将取决于情况和特定的编译器,如果有的话,差异可能非常小。

答案 1 :(得分:2)

foo1中,您按值传递参数(即共享指针)。因此,std::shared_ptr<X>的复制构造函数将被引发(即,当} foo1调用本地副本的析构函数时,ref计数器将增加然后减少

foo2中,您通过const引用传递参数(即共享指针)。因此,您传递原始对象的const限定别名(即,不会增加ref计数器)。

您还可以在以下示例中看到这一点:

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.这是shared_ptr中定义的原始mainfoo1中的副本。然而,在foo2中,参考计数器仍为1。

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

答案 2 :(得分:0)

通常,最好通过引用传递共享指针,因为原子增量往往会降低性能。在你的情况下,它不会引人注意,因为无论如何你都会在之后复制它。