Is the `= default` move constructor equivalent to an element's move constructor?

it

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; } 

?

+69
c ++ constructor c ++ 11 move-semantics default
Aug 17 '13 at 15:41
source share
4 answers

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 allow you to skip the definition of the body.

However, when you declare explicitly-defaulted-functions :

you have to follow some rules

8.4.2. Explicit Default Functions [dcl.fct.def.default]

Definition of a function of the form:

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

called a clearly default definition. A function that is clearly default should

  • - special member function,

  • have the same declared function type (with the possible exception of different ref qualifiers, except that in the case of a copy constructor or copy assignment operator, the parameter type can be a "reference to non-constant T ", where T is the name of the function class -members), as if it were declared implicitly,

  • have no default arguments.

+39
Aug 17 '13 at 16:11
source share
— -

Yes, the default move constructor will perform a phased move of its base and elements, therefore:

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

equivalent to:

 Example(Example&& mE) = default; 

we can see this by going to the C ++ 11 project . 12.8 Copying and moving class objects described in clause 13, which states (my emphasis is on the future)

The copy / move constructor, which by default is not defined as deleted, is implicitly defined if it is danced (3.2) or when it is clearly defaulted after its first declaration. [Note: the copy / move constructor is implicitly defined, even if its odr-use implementation (3.2, 12.2). -end note] [...]

and paragraph 15, which states:

the implicit copy / move constructor for a non-unit class X performs phased copy / move of its bases and elements . [Note: copied or equal initializers of non-static data elements are ignored. See also the example in 12.6.2. -end note] The initialization order is the same as the order of initialization of the basis and members in a user-defined constructor (see 12.6.2). Let x be either a constructor parameter or, for a move constructor, xvalue, referring to the parameter. Each basic or non-static data element is copied / moved according to its type:

  • if the element is an array, each element is initialized directly with the corresponding subobject x;
  • if the element m has the reference type rvalue T & &, it is directly initialized static_cast (xm);
  • otherwise, the base or element is directly initialized with the corresponding base or element x.

Subobjects of a virtual base class should only be initialized once an implicitly defined copy / move constructor (see 12.6.2).

+17
Aug 04 '14 at 17:03
source share

Is the =default move constructor equivalent to the member move constructor?

Yes. Update: Well, not always. Take a 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 } 

This prints:

 copy 

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

You declared the default move constructor, but instead of moving, copying occurs. What for? Because, if a class has at least one fixed member, then the explicitly specified default constructor of the move is implicitly deleted (such a pun). Therefore, when you run has_nonmovable d = std::move(c) , the copy constructor is actually called because the move constructor from has_nonmovable is deleted (implicitly), it simply does not exist (even if you explicitly declared the move constructor the expression has_nonmovable(has_nonmovable &&) = default ).

But if the non_movable move non_movable not declared, the move constructor would be used for movable (and for every member that has a move constructor), and the copy constructor would be used for nonmovable (and for every member that didn't define a move constructor). See an example:

 #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)); } 

This prints:

 movable::move nonmovable::copy 

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

Update: but if you comment out the line has_nonmovable(has_nonmovable &&) = default; , then a copy will be used for both participants: http://coliru.stacked-crooked.com/a/171fd0ce335327cd - prints:

 movable::copy nonmovable::copy 

So probably setting =default makes sense everywhere. This does not mean that your expressions of movement will always move, but it increases the chances of it.

Another update: But if you comment out the line has_nonmovable(const has_nonmovable &) = default; either, the result will be:

 movable::move nonmovable::copy 

So if you want to know what is going on in your program, just do it yourself: sigh:

+4
Feb 26 '18 at 11:38
source share

very pathological cases share ... YES.

To be more precise, you should also consider possible Example databases that have the same rules. First the basics - in the order of declaration - then the members, always in the order of announcement.

-one
Aug 17 '13 at 15:49
source share



All Articles