这是
struct Example {
int a, b;
Example(int mA, int mB) : a{mA}, b{mB} { }
Example(const Example& mE) : a{mE.a}, b{mE.b} { }
Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { }
Example& operator=(const Example& mE) { a = mE.a; b = mE.b; return *this; }
Example& operator=(Example&& mE) { a = move(mE.a); b = move(mE.b); return *this; }
}
相当于此
struct Example {
int a, b;
Example(int mA, int mB) : a{mA}, b{mB} { }
Example(const Example& mE) = default;
Example(Example&& mE) = default;
Example& operator=(const Example& mE) = default;
Example& operator=(Example&& mE) = default;
}
答案 0 :(得分:43)
是的,两者都是一样的。
但是
struct Example {
int a, b;
Example(int mA, int mB) : a{mA}, b{mB} { }
Example(const Example& mE) = default;
Example(Example&& mE) = default;
Example& operator=(const 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 ;
称为显式默认定义。明确默认的函数
是一个特殊的会员功能,
具有相同的声明函数类型(可能不同的 ref-qualifiers 除外,在复制构造函数或复制赋值运算符的情况下,参数类型可能是“引用非const
T
“,其中T
是成员函数类的名称),就像它已被隐式声明一样,没有默认参数。
答案 1 :(得分:18)
是的,默认的移动构造函数将执行其基础和成员的成员移动,因此:
Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { }
相当于:
Example(Example&& mE) = default;
我们可以通过转到draft C++11 standard部分12.8
复制和移动类对象段 13 来看到这一点(强调我的前进):
默认且未定义为已删除的复制/移动构造函数 是隐含定义的,如果它是odrused(3.2)或明确定义的话 在第一次宣布后违约。 [注:复制/移动 即使实现被省略,也会隐式定义构造函数 它的使用(3.2,12.2)。 - 尾注] [...]
和 15 段落说:
非联合类X的隐式定义的复制/移动构造函数 执行其基础和成员的成员复制/移动。 [ 注意: 将忽略非静态数据成员的brace-or-equal-initializers。 另请参见12.6.2中的示例。 - 结束注意]的顺序 初始化与base的初始化顺序相同 用户定义的构造函数中的成员(见12.6.2)。设x是其中之一 构造函数的参数,或者,对于移动构造函数,一个 xvalue引用参数。每个基础或非静态数据成员 以适合其类型的方式复制/移动:
- 如果成员是一个数组,则使用x的相应子对象直接初始化每个元素;
- 如果成员m具有右值参考类型T&&,则使用static_cast(x.m)进行直接初始化;
- 否则,使用x的相应基数或成员对基础或成员进行直接初始化。
虚拟基类子对象只能被初始化一次 隐式定义的复制/移动构造函数(见12.6.2)。
答案 2 :(得分:7)
=default
移动构造函数是否等同于成员移动构造函数?
是。 更新:嗯,并非总是如此。看看这个例子:
#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
您声明了默认的移动构造函数,但是复制发生而不是移动。为什么?因为如果一个类甚至只有一个不可移动的成员,那么 显式默认的移动构造函数是 隐式已删除(这样的双关语)。因此,当您运行has_nonmovable d = std::move(c)
时,实际上会调用复制构造函数,因为has_nonmovable
的移动构造函数被删除(隐式),它只是不存在(即使您通过表达式显式声明了移动构造函数) has_nonmovable(has_nonmovable &&) = default
)。
但是如果non_movable
的移动构造函数根本没有被声明,则移动构造函数将用于movable
(并且对于具有移动构造函数的每个成员),并且将使用复制构造函数for nonmovable
(以及没有定义移动构造函数的每个成员)。参见示例:
#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 - 打印:
movable::copy
nonmovable::copy
因此,将=default
放在任何地方仍然有意义。这并不意味着你的移动表达式总是会移动,但它会让这种移动表达更高。
还有一次更新:但是如果注释掉has_nonmovable(const has_nonmovable &) = default;
行,那么结果将是:
movable::move
nonmovable::copy
因此,如果您想知道您的计划中发生了什么,请自己做所有事情:感叹:
答案 3 :(得分:-1)
除了非常病态的病例......是的。
更准确地说,您还必须考虑具有完全相同规则的最终基础Example
。首先是基数-in声明顺序 - 然后是成员,始终按声明顺序。