我在20世纪90年代学过C ++,但从那时起就没有多少用过它。我在过去的几十年中试图通过在我工作的小型图书馆中使用现代技术来追赶。我已经遇到过这个风格问题,我想知道现代共识是什么。
我有一个纯虚拟基类Base
,有两个实现A
和B
。实现不在头文件中;他们的公共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;
}
再次,这里有一些限制我为自己添加以保持超级清洁:
A
和B
是实施细节,因此我不会让它们在外部可见。unique_ptr<Base>
而不是unique_ptr<A>
和unique_ptr<B>
。Initialize
方法,我必须返回一个左值。make_unique
使用unique_ptr(new ...)
代替download()
。构建此类事物的常用方法是什么?
答案 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 ++编写的。
但同样,你的设计很好,只有在你真的想要避免动作的情况下才能诉诸我的建议。