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

How to pass a shared_ptr to a mutable object as a parameter?

本文关键字:参数传递 对象 shared ptr      更新时间:2023-10-16

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

通过值传递shared_ptr的第一种方法是引用,因此本身不需要通过引用传递。这样做的明显问题是复制引用,这表明存在一些引用计数开销。

void foo (shared_ptr<bar> p)

第二种方法是通过const引用传递shared_ptr,避免复制shared_ptr实例,但意味着对被引用对象的访问需要两层解引用,而不是一层。

void foo (const shared_ptr<bar> &p)

在实践中,这些理论开销通常是微不足道的。这向我表明,与其为每个个案选择一种或另一种方法,我几乎应该始终遵循一些标准惯例。这就引出了一个问题。。。

有没有一个标准的惯例,我通常应该选择这些方法中的哪一种?如果是这样,传统的选择是什么?

EDIT-可能值得一提-考虑按常量引用传递的一个原因是,有一个预先存在的约定,即大多数类/结构实例都是按常量引用而不是按值传递的,并且shared_ptr是一个类。当然,它不是一个重量级的类别(复制的成本很小(,所以旧惯例背后的原因可能不适用。

始终按值传递shared_ptr s。如果传递引用,您可能会遇到这样的问题:对shared_ptr管理的对象的函数的调用可能只会重置它,现在您有一个悬空指针。如果通过值传递,则可以确保对象在当前函数调用中仍然存在。

请参阅此处了解更多信息。


示例:

#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引用传递——例如,请参阅http://ideone.com/1IYyCBenjamin Lindley在评论中指出。

然而,这类问题的更复杂的变化确实是在实践中偶然出现的。例如,这就是为什么我们被警告迭代器(以及const引用返回值(会被变异引用容器的方法无效的原因。一般来说,这些规则很容易遵循,但偶尔更间接和意想不到的例子会让人大吃一惊。

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

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

我一直在传递const&基于这样一种想法,即在调用堆栈的某个地方,应该有人持有sharedptr的副本,因此在我的整个执行过程中,它的寿命是有保障的。

如果您在另一个线程上执行,则需要一个副本,因此存储shared_ptr的任何人(不仅仅是在方法期间使用它(都需要存储副本,而不是引用。

而且,既然我已经写了这篇文章,我将去阅读为什么人们似乎支持相反的心态。

@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不会出现这种情况。