【问题标题】:std::unique_ptr and std::shared_ptr as parameters for virtual functionsstd::unique_ptr 和 std::shared_ptr 作为虚函数的参数
【发布时间】:2018-01-02 05:11:49
【问题描述】:

我正在设计一个基于 virtual 方法的 C++ 类接口,以便能够提供扩展点。

许多这些公共方法需要heap 分配的对象作为参数。

由于我正在使用现代 C++ 模式,因此我打算为此使用 std::unique_ptrstd::shared_ptr,但我对它们都存有疑问。

使用 std::unique_ptr 看起来像这样:

class IFoo {
  virtual void doSomethingWithUser(std::unique_ptr<User> user) = 0;
}

强制调用者提供std::unique_ptr 有缺点:

  • 调用者无法对提供的用户执行任何操作,因为它必须被移动
  • 如果任何doSomethingWithUser 实现需要将用户存储在某个容器中,则不能从std::shared_ptr 构造

对所有公共方法使用std::shared_ptr 可以解决问题,但我们必须支付额外的内存空间以及引用计数的原子递增和递减。

有什么我可以遵循的经验法则吗?

【问题讨论】:

  • “许多这些公共方法需要堆分配的对象作为参数。”嗯?这是什么意思?
  • @FredLarson 如上例所示,用户是堆分配的,它不在堆栈上。 (用户不能被设计复制,因此需要堆分配它)
  • 我看不出堆与堆栈分配有什么关系。你的意思是你需要通过指针(或引用)而不是值传递?
  • @FredLarson 完全正确
  • @steazzalini 不可复制与需要堆分配无关。我的大部分课程都是堆栈分配的,但只能移动。如果移动不是一个选项,或者您需要具有指向值所有权的多态性,您可能需要堆分配。

标签: c++ interface heap-memory shared-ptr unique-ptr


【解决方案1】:

如果doSomethingWithUser 不需要所有权,则不应将其转移到此方法。

确实,复制共享指针或移动唯一指针有效地转移了资源的所有权。

您的函数参数应该反映您对所传递资源的假定所有权的意图。

如果您只需要观察该值并可能对其进行变异,则应将非拥有句柄传递给您的函数。

如果您需要使资源保持活动状态并可能删除它,那么您应该传递一个拥有句柄,无论它是共享它的唯一所有权。

在您的情况下,函数的名称告诉我您需要“与用户做某事”,而不包含它通过调用者的生命周期。所以你应该传递一个非拥有的句柄。该句柄可以是User*User&amp;,甚至是std::reference_wrapper&lt;User&gt;boost::optional&lt;User&amp;&gt;,具体取决于您的需要。

你的接口确实应该表达一个对象应该能够做什么,并且确实强制每个函数应该采用什么参数,但是你的接口还应该表达它对其参数的所有权。

我通常更喜欢引用,因为它们确保它不能为空并且与自动存储中的对象一起工作。有些人可能会争辩说他们更喜欢将原始指针作为非空非拥有句柄,但我强烈不同意这一点,因为它们强制使用 &amp;object 语法并允许为空。

非拥有原始指针没有错。但是,在现代 C++ 中不应使用原始拥有指针。

【讨论】:

  • 您可能还提到了weak_ptr,因为这是函数使用但不维护数据所有权的语义指示。
  • > 我通常更喜欢引用,因为它们确保它不能为空并且与自动存储中的对象一起工作,但这主要是一个品味问题。呃,不是真的。在您对对象进行变异的极少数情况下,会提出某种糟糕的、被误导的论点(半开玩笑)。但是通过指向 const 而不是 const ref 的指针传递不能为 null 的东西太可怕了,根本不是品味问题。
  • @wphicks std::weak_ptr 仍然是共享所有权,但仍然是非所有权句柄。
  • 你说得对。参考第二段here,以防有人和我有同样的误解。
  • 我完全同意你的看法@GuillaumeRacicot,但对于我无法控制的第 3 方实施,问题仍然存在。我不能对可能的实现做出假设或设置限制。例如,如果某些实现决定缓存传递的用户并且我选择使用引用,那么事情就行不通了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-23
  • 1970-01-01
  • 1970-01-01
  • 2017-08-13
  • 1970-01-01
  • 1970-01-01
  • 2020-01-27
相关资源
最近更新 更多