如何将shared_ptr作为参数传递给可变对象?

时间:2011-12-04 21:10:25

标签: c++ boost c++11 smart-pointers

我想通过智能指针引用将对象传递给函数。该函数可能会更改引用对象的值,但可能不会更改引用本身。有两种明显的方法可以解决这个问题。

第一种通过值传递shared_ptr的方法 - 它引用,因此不需要通过引用传递它。显而易见的问题是复制引用,这表明有一些引用计数开销。

void foo (shared_ptr<bar> p)

第二种方法是通过const引用传递shared_ptr - 避免复制shared_ptr实例,而是暗示对引用对象的访问需要两层解除引用而不是一层。

void foo (const shared_ptr<bar> &p)

在实践中,这些理论上的开销通常是微不足道的,无关紧要的。这告诉我,我不应该为每个案例选择一种方法,而应该遵循一些标准惯例。这导致了这个问题......

我通常应该选择哪种方法的标准惯例?如果是这样,这是传统的选择吗?

编辑 - 可能值得一提 - 考虑const-by-const-reference案例的一个原因是因为有一个预先存在的约定,大多数类/结构实例都是由const传递的-reference而不是value,shared_ptr是一个类。当然,它不是一个重量级的(复制成本很小),因此旧约定背后的原因可能不适用。

4 个答案:

答案 0 :(得分:13)

始终按值shared_ptr传递。如果你传递了一个引用,你可能会遇到这样的问题,即shared_ptr管理的对象函数的调用可能只是重置它,现在你有一个悬空指针。如果传递值,则确保该对象在当前函数调用后仍然存在。

有关更多信息,请参阅here


示例:

#include <memory>
#include <iostream>

std::shared_ptr<int> ptr(new int(42));

void foo(){
  ptr.reset();
}

void bar(std::shared_ptr<int> const& p){
  foo();
  std::cout << *p;
}

int main(){
  bar(ptr);
}

这应该用一点盐来服用。它可以用来证明const-reference不应该传递任何类型 - 参见例如http://ideone.com/1IYyC,Benjamin Lindley在评论中指出。

但是,在实践中偶然会出现这种问题的更复杂的变化。例如,这就是为什么我们被警告为什么迭代器(以及const-reference返回值)被改变引用容器的方法无效。这些规则很容易遵循,但偶尔会有更多间接和意外的例子让人感到意外。

在这种情况下,最好在不需要时避免额外的引用层。

答案 1 :(得分:0)

如果操作对象的函数如果对象包含在智能指针中则不应该相关。它应该接受T&。一些操纵值的自由函数被认为是坏的风格。通过引用const来获取对象并返回一个新值可以更清晰。

答案 2 :(得分:0)

我一直在路过const&amp;基于这样的想法,即某个调用堆栈的某个人应该持有shared_ptr的副本,因此我的整个执行都可以保证它的生命。

如果您在另一个线程上执行,则需要一个副本 - 对于那个存储 shared_ptr的任何人(不仅仅是在他们的方法持续时间内使用它)需要存储副本,而不是参考。

而且,既然我已经写过,我会去阅读为什么人们似乎支持相反的心态。

答案 3 :(得分:-1)

@Xeo说的一个例子:

void foo(shared_ptr<bar> &p)
{
    p.reset(); // ref_count == 0; memory is freed.
}

shared_ptr<bar> p(new bar); // ref_count == 1
foo(p);

const shared_ptr<bar> &p不会发生这种情况。