C++ `=default` 移动构造函数是否等同于成员移动构造函数?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18290523/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is a `=default` move constructor equivalent to a member-wise move constructor?
提问by Vittorio Romeo
Is this
这是
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; }
}
equivalent to 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;
}
?
?
采纳答案by Pierre Fourgeaud
Yes both are the same.
是的,两者都是一样的。
But
但
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;
}
This version will permits you to skip the body definition.
此版本将允许您跳过主体定义。
However, you have to follow some rules when you declare explicitly-defaulted-functions
:
但是,您在声明时必须遵循一些规则explicitly-defaulted-functions
:
8.4.2 Explicitly-defaulted functions [dcl.fct.def.default]
A function definition of the form:
attribute-speci?er-seqopt decl-speci?er-seqopt declarator virt-speci?er-seqopt = default ;
is called an explicitly-defaulteddefinition. A function that is explicitly defaulted shall
be a special member function,
have the same declared function type (except for possibly differing ref-qualifiersand except that in the case of a copy constructor or copy assignment operator, the parameter type may be “reference to non-const
T
”, whereT
is the name of the member function's class) as if it had been implicitly declared,not have default arguments.
8.4.2 显式默认函数 [dcl.fct.def.default]
形式的函数定义:
attribute-speci?er-seqopt decl-speci?er-seqopt declarator virt-speci?er-seqopt = default ;
称为显式默认定义。显式默认的函数应
是一个特殊的成员函数,
具有相同的声明函数类型(除了可能不同的ref 限定符以及在复制构造函数或复制赋值运算符的情况下,参数类型可能是“对非常量的引用
T
”,其中T
是成员函数的名称class) 就好像它已被隐式声明一样,没有默认参数。
回答by Shafik Yaghmour
Yes, a defaulted move constructor will perform a member-wise move of its base and members, so:
是的,默认的移动构造函数将执行其基类和成员的成员移动,因此:
Example(Example&& mE) : a{move(mE.a)}, b{move(mE.b)} { }
is equivalent to:
相当于:
Example(Example&& mE) = default;
we can see this by going to the draft C++11 standardsection 12.8
Copying and moving class objectsparagraph 13which says (emphasis mine going forward):
我们可以通过转到C++11 标准草案部分12.8
复制和移动类对象第13段来看到这一点,其中说(强调我的未来):
A copy/move constructor that is defaulted and not defined as deleted is implicitly definedif it is odrused (3.2) or when it is explicitly defaulted after its first declaration. [ Note: The copy/move constructor is implicitly defined even if the implementation elided its odr-use (3.2, 12.2). —end note ][...]
如果它被 odrused (3.2) 或在它的第一次声明后显式默认,则默认且未定义为已删除的复制/移动构造函数 是隐式定义的。[ 注意:即使实现省略了其 odr-use (3.2, 12.2),复制/移动构造函数也是隐式定义的。— 尾注 ][...]
and paragraph 15which says:
和第15段说:
The implicitly-defined copy/move constructorfor a non-union class X performs a memberwise copy/move of its bases and members. [ Note: brace-or-equal-initializers of non-static data members are ignored. See also the example in 12.6.2. —end note ] The order of initialization is the same as the order of initialization of bases and members in a user-defined constructor (see 12.6.2). Let x be either the parameter of the constructor or, for the move constructor, an xvalue referring to the parameter. Each base or non-static data member is copied/moved in the manner appropriate to its type:
- if the member is an array, each element is direct-initialized with the corresponding subobject of x;
- if a member m has rvalue reference type T&&, it is direct-initialized with static_cast(x.m);
- otherwise, the base or member is direct-initialized with the corresponding base or member of x.
Virtual base class subobjects shall be initialized only once by the implicitly-defined copy/move constructor (see 12.6.2).
非联合类 X 的隐式定义的复制/移动构造函数执行其基类和成员的成员复制/移动。[ 注意:非静态数据成员的括号或相等初始化器被忽略。另请参见 12.6.2 中的示例。—end note ] 初始化的顺序与用户定义的构造函数中基类和成员的初始化顺序相同(见 12.6.2)。让 x 要么是构造函数的参数,要么是移动构造函数的 xvalue 引用参数。每个基本或非静态数据成员都以适合其类型的方式复制/移动:
- 如果成员是数组,则每个元素直接用x的对应子对象初始化;
- 如果成员 m 具有右值引用类型 T&&,则使用 static_cast(xm) 直接初始化;
- 否则,使用 x 的对应基或成员直接初始化基或成员。
虚拟基类子对象只能由隐式定义的复制/移动构造函数初始化一次(见 12.6.2)。
回答by anton_rh
Is a
=default
move constructor equivalent to a member-wise move constructor?
是一个
=default
移动的构造相当于一个成员明智之举构造?
Yes. Update:Well, not always. Look at this example:
是的。更新:嗯,并非总是如此。看这个例子:
#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
}
It prints:
它打印:
copy
http://coliru.stacked-crooked.com/a/62c0a0aaec15b0eb
http://coliru.stacked-crooked.com/a/62c0a0aaec15b0eb
You declared defaulted move constructor, but copying happens instead of moving. Why? Because if a class has even a single non-movable member then the explicitlydefaultedmove constructor is implicitlydeleted(such a pun). So when you run has_nonmovable d = std::move(c)
, the copy constructor is actually called, because the move constructor of has_nonmovable
is deleted (implicitly), it just doesn't exists (even though you explicitly declared the move constructor by expression has_nonmovable(has_nonmovable &&) = default
).
您声明了默认的移动构造函数,但发生的是复制而不是移动。为什么?因为如果一个类甚至有一个不可移动的成员,那么显式默认的移动构造函数就会被隐式删除(比如双关语)。因此,当您运行时has_nonmovable d = std::move(c)
,实际上调用了复制构造函数,因为has_nonmovable
删除了(隐式)的移动构造函数,它只是不存在(即使您通过表达式显式声明了移动构造函数has_nonmovable(has_nonmovable &&) = default
)。
But if the move constructor of non_movable
was not declared at all, the move constructor would be used for movable
(and for every member that has the move constructor) and the copy constructor would be used for nonmovable
(and for every member that does not define the move constructor). See the example:
但是,如果non_movable
根本没有声明 的移动构造函数,则移动构造函数将用于movable
(以及每个具有移动构造函数的成员),而复制构造函数将用于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));
}
It prints:
它打印:
movable::move
nonmovable::copy
http://coliru.stacked-crooked.com/a/420cc6c80ddac407
http://coliru.stacked-crooked.com/a/420cc6c80ddac407
Update:But if you comment out the line has_nonmovable(has_nonmovable &&) = default;
, then copy will be used for both members: http://coliru.stacked-crooked.com/a/171fd0ce335327cd- prints:
更新:但如果您注释掉该行has_nonmovable(has_nonmovable &&) = default;
,则副本将用于两个成员:http: //coliru.stacked-crooked.com/a/171fd0ce335327cd- 打印:
movable::copy
nonmovable::copy
So probably putting =default
everywhere still makes sense. It doesn't mean that your move expressions will always move, but it makes chances of this higher.
所以可能=default
到处放仍然有意义。这并不意味着您的移动表达式将始终移动,但它使这种可能性更高。
One more update:But if comment out the line has_nonmovable(const has_nonmovable &) = default;
either, then the result will be:
还有一个更新:但是如果注释掉该行has_nonmovable(const has_nonmovable &) = default;
,那么结果将是:
movable::move
nonmovable::copy
So if you want to know what happens in your program, just do everything by yourself :sigh:
因此,如果您想知道程序中发生了什么,只需自己做所有事情 :sigh:
回答by Emilio Garavaglia
apart very pathological cases ... YES.
除了非常病态的情况……是的。
To be more precise, you have also to considered eventual bases Example
may have, with exact same rules. First the bases -in declaration order- then the members, always in declaration order.
更准确地说,您还必须考虑最终的基础Example
可能具有完全相同的规则。首先是基类 - 按声明顺序 - 然后是成员,总是按声明顺序。