C++11:按值调用、 move 语义和继承

标签 c++ inheritance c++11 move move-semantics

假设我有一个类,我打算将其直接公开为可实例化的类 对程序员:

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/

相关文章:

WPF 控件继承

javascript - 合并两个原型(prototype)链

c++ - 在 C++0x 中,非静态数据成员初始化器会覆盖隐式复制构造函数吗?

c++ - 快速排序算法不起作用

c++ - 使用 std::vector<double> 访问 std::unique_ptr<double[2]> 管理的数据

c++ - Fortran C++ 链接库

c++ - 如何将 basic_ostringstream 与有状态自定义分配器一起使用? (C++11)

c# - 关于继承 C#

c++ - 存储需要精确匹配和最接近匹配的值的最佳结构

c++ - 从作为模板参数传递给构造函数的类继承并从它们继承