std::unique_ptr 和 std::shared_ptr 作为虚函数的参数

std::unique_ptr and std::shared_ptr as parameters for virtual functions

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

许多 public 方法需要 heap 分配的对象作为参数。

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

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

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

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

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

有没有我可以遵循的经验法则?

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

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

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

如果您只需要观察值,并可能改变它,您应该将非拥有句柄传递给您的函数。

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

在你的情况下,函数的名称告诉我你需要 "do something with the user",而不包含它通过调用者的生命周期。所以你应该传递一个非拥有句柄。该句柄可以是 User*User&,甚至可以是 std::reference_wrapper<User>boost::optional<User&>,具体取决于您的需要。

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

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

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