C++11 移动构造函数

C++11 move constructor

本文关键字:构造函数 移动 C++11      更新时间:2023-10-16


考虑到以下类,实现移动构造函数的正确方法是什么:

class C {
public:
    C();
    C(C&& c);
private:
    std::string string;
}

当然,这个想法是避免复制string或两次解除分配。
让我们假设基本示例只是为了清楚起见,我确实需要一个移动构造函数。


我试过了:

C::C(C&& c) {
    //move ctor
    string = std::move(c.string);
}

C::C(C&& c) : string(std::move(c.string)) {
    //move ctor
}

两者都在 gcc 4.8 上编译良好且运行良好。选项A似乎是正确的行为,string被复制而不是与选项B一起移动。
这是移动构造函数的正确实现吗?

由于std::string本身有一个移动 ctor,因此隐式定义的 move-ctor 用于C将负责正确的移动操作。您可能无法自己定义它。但是,如果您有任何其他数据成员,特别是:

12.8 复制和移动类对象

12 隐式声明的复制/移动构造函数是内联公共其类的成员。类 X 的默认复制/move 构造函数定义为已删除 (8.4.3(,如果 X 具有:

— 具有非平凡的对应构造函数和 X 是一个类似联合的类,

— 一类类型 M(或其数组(的非静态数据成员,不能被复制/移动,因为重载分辨率 (13.3(,应用于 M相应的构造函数,导致歧义或函数从默认构造函数中删除或无法访问,或者

— 一无法复制/移动的直接或虚拟基类 B,因为过载分辨率 (13.3(,适用于 B 的相应构造函数,导致歧义或删除函数或无法从默认构造函数访问,或

— 为了搬家构造函数、非静态数据成员或直接或虚拟基类使用没有移动构造函数且不平凡的类型可复制。

13 类 X 的复制/移动构造函数是微不足道的,如果它是既不是用户提供也不是删除的,如果

— 类 X 没有虚函数 (10.3( 和 没有虚拟基类 (10.1(,以及函数 (10.3( 和没有虚拟基类 (10.1(,以及

— 该选择用于复制/移动每个直接基类子对象的构造函数是琐碎,以及

— 对于 X 的每个非静态数据成员,该成员属于类类型(或其数组(,选择复制/移动该构造函数成员是微不足道的;否则,复制/移动构造函数是不平凡的。

您可能希望实现自己的移动控制。

如果需要 move-ctor,请首选初始值设定项列表语法。总是!否则,您最终可能会得到初始值设定项列表中未提及的每个对象的默认构造(这是仅对具有非默认 ctor 的成员对象强制使用的内容(。

您的两个变体都将移动字符串。应该首选第二个变体,因为它不会默认构造一个空字符串只是为了稍后移动分配它。

检查

你的测试用例,然后检查编译器的bugzilla列表。如果要确保这两种情况都移动,则需要跟踪对string::operator=(string&&)(第一种情况(string::string(string&&)(第2种情况(的调用。

两个构造函数都应该工作。所以两者都是正确的移动构造函数。第二个可能更有效率,因为第一个默认构造string分配给它,而第二个将简单地移动构造它,因此应该更有效率。如果第二个效率较低,我会怀疑编译器错误(请记住,当前编译器的 C++11 支持仍然不完整(或有缺陷的测试方法(您究竟如何测试复制与移动,并且您确定在这两种情况下都调用移动构造函数而不是赋值操作?

当然,只要有可能,您就可以简单地让编译器通过 C(C&&) = default; 生成您的构造函数。

这里不需要实现移动构造函数,因为您不必手动管理内存。仅当您在类中手动使用动态数组时,Move 构造函数才有用。

您仍然可以显式地让编译器创建默认的移动构造函数,即使您没有请求它,它也应该已经完成:

C(C&& c) = default;