C++ - 指针传递问题

3

有人知道如何传递 boost::shared_ptr - 通过值或引用?

在我的平台上(32位),sizeof(shared_ptr)为8个字节,看起来应该通过引用传递它们,但也许有人有另一种观点/进行了配置文件/类似的东西吗?

5个回答

5
在C++中,基于对象的大小来选择传值还是传引用通常不是一个好主意。部分原因是编译器通常会对传值进行复制省略,从而抵消了复制值的成本,但主要原因是这两个选项经常表现出不同的行为。因此,应该选择最能表达你需要做的事情的选项。对于shared_ptr来说,它存在的全部原因就是它可以被复制,以便多个对象可以共享所指向的对象的所有权。如果你从未通过值传递shared_ptr,那么你可能会开始怀疑它到底是不是一个shared_ptr。在这种情况下,scoped_ptr可能是一种更有效的解决方案。显然,并不是说你总是应该通过值传递shared_ptr,只是传值是它们的常见用例之一。如果需要调用者和被调用者共享所有权,请通过值传递。如果不希望被调用者拥有任何类型的所有权,请通过引用传递。

我曾见过一些MT代码的性能受到了严重影响,因为复制智能指针会导致引用计数的原子增加和减少带来很多开销。在一些策略性地改变传值方式为传引用后,性能从差到好。自那时起,我认为传引用可能应该成为默认选项。 - sbi
@sbi:我的观点只是,如果你一直通过引用传递shared_ptr,那么它一开始就没有成为shared_ptr的意义。然后你可以完全摆脱引用计数器。如果你几乎从不想增加/减少引用计数器,你应该考虑为什么要使用引用计数智能指针。因此,也许我的观点不是“默认按值传递”,而是“默认使用另一种智能指针类型,并在需要引用计数器时回退到shared_ptr(这是因为你需要存储多个副本,所以按值传递是有意义的)”。 - jalf
看起来这是一个好的观点,尽管我很难想出一种根据它来改变代码的方式。也许如果它在设计时就有这个考虑…… - sbi
如果您不希望被调用者拥有任何形式的所有权,请通过引用传递。如果您存在所有权问题,为什么要传递智能指针而不是原始指针呢? - curiousguy

2

尽可能使用shared_ptr的引用,这是因为shared_ptr的操作是原子的,因此开销异常高,并且在增量/减量上可能会出现缓存未命中的情况,如果调用函数仍然具有对象的强引用,则这并不是必要的。

当然,这并非总是可行的-例如,在容器或成员变量中,它们需要持有自己的引用。

正如另一个回答者所说,在C++中任何开销的绝大部分都在构造函数/析构函数中,而不是传递原始位和字节。对于shared_ptr也是如此。


1

我会通过引用传递 shared_ptr 的方式来传递它。如果你通过值传递,使用计数会在进入函数时增加,在离开函数时减少,这是不必要的开销。


如果这样做,每次访问指针都会多一层间接引用。编译器无法将指针值缓存到寄存器中,因为所指向的 shared_ptr 可能会随时间而改变。const 关键字并没有帮助,它不能保证其他线程无法更改所指向的对象。 - user180326
@jdv:编译器是单线程的野兽。它不关心其他线程。如果它所做的优化破坏了多线程,那是你编写的线程代码质量差的问题。编译器会毫不留情地摧毁你的多线程希望。 - Puppy
@Puppy 其他线程不会直接影响,但是你自己的线程可能会,除非你只调用“可内联”函数。 - curiousguy

1

我认为 shared_ptr 的本质是它是一个对象,应该通过值传递。据我回忆,它使用构造函数和析构函数自动处理引用计数,因此它知道何时释放指针。

每当我使用它时,我都会通过值传递。


2
“shared_ptr 的本质是它是一个对象”这句话的确切含义是什么? - fredoverflow
@Fred:它存在的原因是你可以将其视为对象而不是指针。 - James Curran

1
你可以从两个方面来看待这个问题:
  • boost::shared_ptr 是一个对象(应该通过 const & 传递)。

  • boost::shared_ptr 模拟指针,应该像指针一样处理。

两种方式都是有效的,第二种方式会产生额外实例构造和析构的成本(除非你在编写性能关键代码,否则不应该是个大问题)。
有两种情况会应该按值传递:
  • 当您不确定指针类型是否会保持不变时。也就是说,如果您考虑在将来的某个时候在代码库中用T*替换shared_ptr<T>,那么编写typedef shared_ptr<T> TPtr;并将函数定义为void yourfunction(TPtr value)是有意义的。

    在这种情况下,当您更改指针类型时,您只需要修改typedef行。

  • 当您在两个具有不同生命周期的模块之间共享指针时。在这种情况下,您需要确保有两个智能指针实例,并且两者都增加指针的引用计数。

在其他情况下,这是一种偏好问题(除非您正在编写性能关键代码,在这种情况下应遵循不同的规则)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接