通过值或const-ref传递std::shared_ptr,然后存储在容器中

Passing std::shared_ptr by value or const ref and then storing in a container?

本文关键字:然后 存储 ptr shared const-ref 传递 std      更新时间:2023-10-16

考虑以下向量:

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_ptrX推送到向量中,从而增加X的ref计数。第一个函数导致参考计数的额外递增和递减,但这是不必要的。

我的理解正确吗?因此,第二种选择是否更可取?

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。即main中定义的原始shared_ptrfoo1中的副本。而在foo2中,ref计数器保持为1。

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

您应该将函数重写为:

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);
}

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

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

相关文章: