【问题标题】:Passing smart-pointers by reference通过引用传递智能指针
【发布时间】:2013-06-28 15:46:22
【问题描述】:

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

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

例如当前代码:

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

变成

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

MyAnimal 是我封装AnimalPtr 的新包装类。

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

【问题讨论】:

  • 一般来说,存储对智能指针的引用并不是一个好主意,但是当你知道它不会被存储时传递对它的引用通常是可以的,例如这个问题:stackoverflow.com/questions/179105/…跨度>

标签: c++ visual-studio-2005


【解决方案1】:

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

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

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

【讨论】:

  • 实际上,我有点喜欢std::unique_ptr<T> const&——这意味着这是一个拥有的对象,不,你不能拥有它。同样,std::unique_ptr<T>& 的意思是“这是一个拥有的对象,但如果你愿意,你可以更改该所有权”。另一方面,我也喜欢“直通unique_ptr”,你将unique_ptr按值取值,并在返回值中按值返回...
  • @Yakk: std::unique_ptr<T> const& 强制您在用户上选择智能指针,并不必要地阻止使用不受 std::unique_ptr 管理的对象的调用,传递 T& 显然意味着它是一个 拥有 (由某人,某处)对象,并且更灵活(除了启用一定程度的 const 正确性之外,您无法通过 const& 获得智能指针。传递 std::unique_ptr<T>& 在调用者上是否不清楚该对象仍然是我的或您的,您是否声称拥有所有权?或者我可以在调用后使用指针吗?
  • @Yakk:是的,我不是在谈论技术上能够检测到它,而是在编写代码时。从设计的角度来看,拥有一个可能会或可能不会声称拥有所有权的功能是否有意义?实现一个调用它的函数是否有意义,并且在某些情况下它需要对对象执行一些调用后工作,但不做任何事情也可以?我会发现代码很难通过代码审查,除非有非常充分的理由以如此复杂的方式做事
  • +1:当智能指针在整个应用程序中使用时,通过引用传递和通过值传递之间的性能差异变得很大(可测量和可观察),尤其是在调试构建中。您几乎总是希望通过 const 引用传递,如果您需要存储一个副本以供以后使用,您可以使用参数(通过 const 引用传递)按值初始化新实例。
【解决方案2】:

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

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

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

【讨论】:

  • 您可以随时创建指向对象的副本:Foo* f = smart_foo.get(),但您无法保证f 的生命周期。
  • @chad - 是的,将指针指向智能指针总是不安全的。但问题是关于参考与非参考,这两者没有什么不同。
猜你喜欢
  • 2021-07-22
  • 2016-04-06
  • 2014-07-27
  • 2023-03-03
  • 1970-01-01
  • 2021-02-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多