我想通过智能指针引用将对象传递给函数。该函数可能会更改引用对象的值,但可能不会更改引用本身。有两种明显的方法可以解决这个问题。
第一种通过值传递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
是一个类。当然,它不是一个重量级的(复制成本很小),因此旧约定背后的原因可能不适用。
答案 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
不会发生这种情况。