从工厂返回时,可以正确的方法来upcast superty_ptr

Proper way to upcast unique_ptr when returning from a factory

本文关键字:方法 upcast superty ptr 返回 工厂      更新时间:2023-10-16

我在1990年代学习了C ,但是从那时起就没有使用太多。我试图通过在工作中维护的一个小图书馆中使用现代技术来赶上过去几十年。我遇到了这个风格的问题,我想知道什么是现代共识。

我有一个纯虚拟基类Base,有两个实现AB。实现不在标题文件中;他们的公共API完全是Base的一部分。我具有构造它们的工厂功能,需要调用一个共同的初始化器。这些课程不支持复制,并且可以在其一生中更改所有者,因此我使用unique_ptr来保持更理智。

组合,这导致了一个尴尬的结构:

unique_ptr<Base> rv = make_unique<A>();

我尚未看到make_unique明确给出模板类的情况。我还没有看到make_unique不能与auto一起使用的情况。但是,如果我希望RVO应用,则rv(AFAICT(需要具有type unique_ptr<Base>而不是unique_ptr<A>

在这里,我在一行中与"我之前见过的东西"有两个偏差。那引发了我脑海中的旗帜,让我认为我应该向社区寻求集体智慧。

好的,足够英语;这是一些代码:

class Base {
 public:
  static std::unique_ptr<Base> MakeA();
  static std::unique_ptr<Base> MakeB();
 private:
  void Initialize();
};
class A : public Base {};
class B : public Base {};
std::unique_ptr<Base> Base::MakeA() {
  std::unique_ptr<Base> rv = std::make_unique<A>();
  rv->Initialize();
  return rv;
}
std::unique_ptr<Base> Base::MakeB() {
  std::unique_ptr<Base> rv = std::make_unique<B>();
  rv->Initialize();
  return rv;
}

再次,这是我为自己添加的一些限制,以使事情保持超级清洁:

  • 由于AB类是实现细节,因此我不让它们外部可见。
  • 因此,工厂功能需要返回unique_ptr<Base>而不是unique_ptr<A>unique_ptr<B>
  • 我正在尝试使此NRVO友好,因为我还有其他只有移动的课程可以处理并希望练习使RVO友好的功能。
  • 由于工厂功能必须调用Initialize方法,因此我必须返回lvalue。
  • 出于通常的原因,我想使用make_unique而不是unique_ptr(new ...)

构造这种事情的通常方法是什么?

如果我希望RVO应用,则RV(AFAICT(需要具有type unique_ptr,而不是unique_ptr

由于您实际上没有返回或分配构造的对象(只是(唯一_(指针(,因此RVO在这里是无关紧要的。unique_ptr基本上是零偏头,它是一个指针(即一个寄存器(。它可能会在C 抽象机器(STD :: simel_ptr的构造函数/操作员(方面有所不同,但实际上,这方面不会产生影响。

更重要的是:(移动(分配运算符或a或b的移动/复制构造函数,有或没有(n(rvo。

请注意,这不是unique_ptr特定的 - 如果要返回原始指针,则将适用相同的想法。

您的设计很好。尽管如此,如果您愿意消除返回时的移动/复制,即您的设计是这种情况(当然,如果您的编译器支持这种优化(,您可能还希望在Creation网站上消除它。为此,您需要使用

std::unique_ptr<Base> rv(new Derived(...));

在这里,您应该小心的位置而不是省略号。关于您的评论,new的用法不愿在现代C 中使用。它不是内部使用newmake_unique,它是用现代C 编写的。

但是,再次,您的设计很好,只有在您真的想避免动作时,您才能诉诸我的建议。