假设我有一个类,我打算将其直接公开为可实例化的类 对程序员:
class Base
{
public:
Base(std::string text) : m_text(std::move(text)) {}
private:
std::string m_text;
};
到目前为止一切顺利。这里不需要右值构造函数。 现在,在未来的某个时刻,我决定扩展 Base:
class Derived : public Base
{
public:
Derived(const std::string &text) : Base(text) {}
};
这让我很烦恼:我不能在 Derived 中按值获取字符串,因为那是 Base 已经在做 - 我最终会得到 2 个拷贝和 1 个 move 。这里的 const-reference 构造函数还对右值执行了不必要的复制。
问题:如何在不添加更多构造函数的情况下仅复制 + move 一次(就像 Base 中的简单构造函数那样)?
最佳答案
你不能只复制和 move 一次,除非你改变你的类的设计并将它们的构造函数变成(可能受 SFINAE 约束的)模板转发构造函数(Yakk's answer shows how)。
虽然这样做可以在提供右值时只执行一次 move 而不执行复制,而在提供左值时执行一次复制而不执行任何 move ,但在大多数情况下这是一种矫枉过正。
作为基于模板的转发构造函数的替代方案,您可以在基类和派生类中提供两个构造函数:一个用于右值引用,一个用于左值引用 常数
。但同样,这在大多数情况下都是不必要的复杂化(并且当参数数量增加时不能很好地扩展,因为所需构造函数的数量会呈指数增长)。
move std::string
与复制指针和整数一样快(此处忽略 SSO 优化),除非您有确凿证据表明这是一个瓶颈,否则您不应该为此烦恼这会阻止您的应用程序满足其性能要求(难以置信)。
因此,只需让您的 Derived
构造函数无条件地按值获取其参数,并在将其传递给基类的构造函数时 move 它:
class Derived : public Base
{
public:
Derived(std::string text) : Base(std::move(text)) { }
};
如果您希望(或接受)Derive
继承 所有 Base
的构造函数,另一种选择是利用 C+ +11 的继承构造函数如下:
class Derived : public Base
{
public:
using Base::Base;
// ^^^^^^^^^^^^^^^^^
};
关于C++11:按值调用、 move 语义和继承,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16722614/