从工厂返回时正确的方法来upcast unique_ptr

时间:2018-04-05 08:10:20

标签: c++ factory unique-ptr

我在20世纪90年代学过C ++,但从那时起就没有多少用过它。我在过去的几十年中试图通过在我工作的小型图书馆中使用现代技术来追赶。我已经遇到过这个风格问题,我想知道现代共识是什么。

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

结合起来,这会导致一个有点尴尬的结构:

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

我还没有看到make_unique被明确赋予模板类的情况。我还没有看到make_unique无法与auto一起使用的情况。但是,如果我想要申请RVO,则rv(AFAICT)需要输入unique_ptr<Base>而不是unique_ptr<A>

在这里,我有两个偏离&#34;我之前见过的&#34;在一条线上。这引起了我脑海中的旗帜,让我觉得我应该向社区寻求集体智慧。

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

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方法,我必须返回一个左值。
  • 我想make_unique使用unique_ptr(new ...)代替download()

构建此类事物的常用方法是什么?

2 个答案:

答案 0 :(得分:1)

  

如果我想要申请RVO,那么rv(AFAICT)需要具有unique_ptr类型而不是unique_ptr

由于您实际上没有返回或分配构造对象(只是一个(unique_)指针),因此RVO与此无关。 unique_ptr基本上是零开销,它是一个单指针(即一个寄存器)。它可能会对C ++抽象机器(std :: unique_ptr的构造函数/运算符)产生影响,但实际上这个方面没有任何影响。

更重要的是:无论是(移动)赋值运算符还是A或B的移动/复制构造函数,有或没有(N)RVO。

请注意,这并非特定于unique_ptr - 如果您要返回原始指针,则会应用相同的想法。

答案 1 :(得分:0)

你的设计很好。仍然如果您想要在返回时消除移动/复制(这是您的设计的情况)(当然,如果您的编译器支持这样的优化),您可能还想在创建站点消除它。为此,您需要使用

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

在这里你应该小心你所放置的内容而不是省略号。关于您的评论,不建议在现代C ++中使用new的用法。它不是,make_unique内部使用new,它是用现代C ++编写的。

但同样,你的设计很好,只有在你真的想要避免动作的情况下才能诉诸我的建议。