24

智能指针通常很小,所以按值传递不是问题,但是传递对它们的引用有什么问题吗?或者更确切地说,是否存在不能这样做的特定情况?

我正在编写一个包装库,我的几个类在底层库中包装了智能指针对象......我的类不是智能指针,但 API 当前按值传递智能指针对象。

例如当前代码:

void class::method(const AnimalPtr pAnimal) { ... }

变成

void class::method(const MyAnimal &animal){...}

我的新包装类在哪里MyAnimal封装AnimalPtr

无法保证 Wrapper 类有一天不会超出包装智能指针的范围,因此按值传递让我感到紧张。

4

2 回答 2

30

在大多数情况下,您应该通过引用而不是值来传递共享指针。虽然 a 的大小std::shared_ptr很小,但复制的成本涉及原子操作(概念上是原子增量和销毁副本时的原子减量,尽管我相信一些实现设法进行非原子增量)。

在其他情况下,例如std::unique_ptr您可能更喜欢按值传递,因为副本必须是一个移动,并且它清楚地记录了对象的所有权已转移到函数(如果您不想转移所有权,请传递对真实对象的引用,而不是std::unique_ptr)。

在其他情况下,您的里程可能会有所不同。您需要了解智能指针的复制语义是什么,以及是否需要支付成本。

于 2013-06-28T15:53:45.680 回答
3

通过引用传递智能指针是可以的,除非它是给构造函数的。在构造函数中,可以存储对原始对象的引用,这违反了智能指针的约定。如果这样做,您可能会出现内存损坏。即使您的构造函数今天没有存储引用,我仍然会保持警惕,因为代码会更改,如果您稍后决定需要更长时间地保存变量,这很容易错过。

在普通函数中,您不能将函数参数作为引用存储在任何地方,因为必须在初始化期间设置引用。您可以将引用分配给一些寿命更长的非引用变量,但这将是一个副本,因此会适当地增加其生命周期。因此,无论哪种情况,您都无法在调用函数可能已释放它的情况下继续持有它。在这种情况下,您可能会通过参考获得较小的性能提升,但在大多数情况下我不打算注意到它。

所以我会说 - 构造函数,总是按值传递;其他功能,如果需要,通过引用传递。

于 2013-06-28T17:00:30.327 回答