‘ = default’move 构造函数是否等效于成员方式的 move 构造函数?

就是这个

struct Example {
string a, b;


Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { }
Example& operator=(Example&& mE) { a = move(mE.a); b = move(mE.b); return *this; }
}

相当于这个

struct Example {
string a, b;


Example(Example&& mE)            = default;
Example& operator=(Example&& mE) = default;
}

50519 次浏览

除了非常病态的病例... 是的。

更准确地说,您还必须考虑 Example可能具有的最终碱基,具有完全相同的规则。首先是基数-在声明顺序-然后是成员,总是在声明顺序。

是的,两者都是一样的。

但是

struct Example {
string a, b;


Example(Example&& mE)            = default;
Example& operator=(Example&& mE) = default;
}

这个版本将允许您跳过主体定义。

但是,在声明 explicitly-defaulted-functions时必须遵守一些规则:

8.4.2显式默认函数[ dcl.fct.def.default ]

表单的函数定义:

  attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt = default ;

被称为 明确违约定义。一个明确默认的函数

  • 是一个特殊的成员函数,

  • 具有相同的声明函数类型(除了可能不同的 参考资料修饰符和除了在复制建构子或拷贝赋值操作符的情况下,参数类型可能是“引用非常量 T”,其中 T是成员函数的类的名称) ,就好像它已经被隐式声明,

  • 没有默认参数。

是的,默认的 move 构造函数将对其基础和成员执行成员方式的移动,因此:

Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { }

等同于:

Example(Example&& mE)                 = default;

我们可以从 C + + 11标准草案章节 12.8 复制和移动类对象段落 13看到(强调我的未来) :

默认的、未定义为已删除的复制/移动构造函数 是隐式定义 ,如果它是 odruse (3.2)或当它是显式的 在第一次声明后默认。[注: 复制/移动 构造函数是隐式定义的,即使省略了实现 (3.2,12.2)ー尾注][ ... ]

15段写道:

非联合类 X 的 隐式定义的复制/移动构造函数 对其基础和成员 执行成员方式的复制/移动。[注: 忽略非静态数据成员的大括号或等于初始值设定项。 参见12.6.2中的示例 初始化的顺序与基函数和 用户定义构造函数中的成员(参见12.6.2) 构造函数的参数,或者对于 move 构造函数,为 每个基本数据成员或非静态数据成员 以适合其类型的方式复制/移动:

  • 如果成员是一个数组,则每个元素直接初始化为相应的子对象 x;
  • 如果成员 m 具有右值引用类型 T & & ,则使用 static _ cast (x.m)直接初始化它;
  • 否则,基或成员将使用相应的 x 的基或成员直接初始化。

方法只初始化一次虚拟基类子对象 隐式定义的复制/移动构造函数(见12.6.2)。

=default的 move 构造函数是否等效于成员方式的 move 构造函数?

是的。 更新:好吧,并不总是这样。看看这个例子:

#include <iostream>


struct nonmovable
{
nonmovable() = default;


nonmovable(const nonmovable  &) = default;
nonmovable(      nonmovable &&) = delete;
};


struct movable
{
movable() = default;


movable(const movable  &) { std::cerr << "copy" << std::endl; }
movable(      movable &&) { std::cerr << "move" << std::endl; }
};


struct has_nonmovable
{
movable    a;
nonmovable b;


has_nonmovable() = default;


has_nonmovable(const has_nonmovable  &) = default;
has_nonmovable(      has_nonmovable &&) = default;
};


int main()
{
has_nonmovable c;
has_nonmovable d(std::move(c)); // prints copy
}

它打印:

copy

Http://coliru.stacked-crooked.com/a/62c0a0aaec15b0eb

您声明了默认的 move 构造函数,但是发生的是复制而不是移动。为什么?因为如果一个类有一个不可移动的成员,那么 显式地 默认 move 构造函数就是 < strong > 隐式 删除(这样的双关语)。所以当你运行 has_nonmovable d = std::move(c)时,复制建构子实际上被调用了,因为 has_nonmovable的 move 构造函数被删除了(隐式地) ,它根本不存在(即使你通过表达式 has_nonmovable(has_nonmovable &&) = default显式地声明了 move 构造函数)。

但是如果根本没有声明 non_movable的 move 构造函数,move 构造函数将用于 movable(以及每个拥有 move 构造函数的成员) ,而复制建构子将用于 nonmovable(以及每个没有定义 move 构造函数的成员)。看看这个例子:

#include <iostream>


struct nonmovable
{
nonmovable() = default;


nonmovable(const nonmovable  &) { std::cerr << "nonmovable::copy" << std::endl; }
//nonmovable(      nonmovable &&) = delete;
};


struct movable
{
movable() = default;


movable(const movable  &) { std::cerr << "movable::copy" << std::endl; }
movable(      movable &&) { std::cerr << "movable::move" << std::endl; }
};


struct has_nonmovable
{
movable    a;
nonmovable b;


has_nonmovable() = default;


has_nonmovable(const has_nonmovable  &) = default;
has_nonmovable(      has_nonmovable &&) = default;
};


int main()
{
has_nonmovable c;
has_nonmovable d(std::move(c));
}

它打印:

movable::move
nonmovable::copy

Http://coliru.stacked-crooked.com/a/420cc6c80ddac407

更新: 但是如果你注释掉 has_nonmovable(has_nonmovable &&) = default;行,那么复制将被用于两个成员: http://coliru.stacked-crooked.com/a/171fd0ce335327cd-print:

movable::copy
nonmovable::copy

所以把 =default放在任何地方可能还是有意义的。这并不意味着你的移动表达式将始终移动,但它使这个机会更高。

还有一个更新: 但是如果注释掉 has_nonmovable(const has_nonmovable &) = default;行,那么结果将是:

movable::move
nonmovable::copy

因此,如果你想知道程序中发生了什么,只需要自己做所有的事情: