When/where C++ five constructors (copy/assignment/mmove) are invoked

C++ default , copy, move, assignment constructors

Sometimes it is confusing where/when  the default , copy, move, assignment constructors  in C++ are invoked,  here some are notes:

e.g.:

class A {

public:

A(); // default constructor

A(int i);  // my constructor

A&  A( const A&) ; // copy constructor

A&  A( A&) ; //  another copy constructor

A& operator =(const A&) // assignment constrocutor

~A(); // destrcutor

A( A&& other);  // move constructor, the const form does not make much sense

A& operator=(A&& other); // move assignment

}

// some codes:

A a ; // A::A(): default constructor

A b(1) ; // A::A(int i), my constructor

A c(b) ; // A::A( A& ), copy constructor

A d=b ; // A::A( A& ), copy constructor

A e ; // A::A(): default constructor

e = b ; // assigment constructor

A g=std::move(e) ; // A::A( const A&& ), move constructor

A A g1;// A::A(): default constructor

g1=std::move(e) ;  //move assignment constructor

const A x=f() ; // A f(): { A a; return a; }

A::A(): default constructor
just before return

A y(x) ; // A::A( const A& ), const copy constructor

A z(x) ; // A::A( A& ), copy constructor

 

Some interesting functions:

A&& f1() {  A a; return std::move(a); }

A f2(A a): { return a; }

A f3(A&& a): { return a; }

A f4(A& a) { return a; }

 The output are:

A w=f1() ; // A&& f1(): { A a; return std::move(a) }
A::A(): default constructor
just before return
~A() destrcutor
A::A( const A&& ), move constructor

A w=f2(a) ; // A::A( A& ), copy constructor
A f2(A a): { return a }
just before return                                  <— this is interesting
A::A( const A&& ), move constructor
~A() destrcutor

f3(std::move(a)) ; // A f3(A&& a): { return a }
just before return                                       <— this is interesting
A::A( A& ), copy constructor
~A() destrcutor

f4(b) ; // A f4(A& a): { return a }
just before return
A::A( A& ), copy constructor

 

The presence of a user-defined destructor, copy-constructor, or copy-assignment operator prevents implicit definition of the move constructor and the move assignment operator.

The generation of the implicitly-defined copy constructor is deprecated if T has a user-defined destructor or user-defined copy assignment operator.

It is not easy to remember those rules, I guess it is best to declare those five constructor explicitly.

Multiple copy constructors:

A copy constructor of class T is a non-template constructor whose first parameter is T&, const T&, volatile T&, or const volatile T&, and either there are no other parameters, or the rest of the parameters all have default values.

So it is totally legal to have multiple copy constructors with different signatures

A(const A&) could be used for both cost or non-const parameters, but not the other way around.

 

Notes: const applies to the thing left of it. If there is nothing on the left then it applies to the thing right of it.

Object * const obj;        // read right-to-left:  const pointer to Object
Object const * obj;        // read right-to-left:  pointer to const Object
Object const * const obj;  // read right-to-left:  const pointer to const Object

 

Some general guidelines:

  • Use f(const X &) if you need just to read from the element.
  • Use f(X) if you need to take the ownership of the object passed. The caller of your function can just do f( std::move(something)) or f(something) when appropriate.
  • Use f(X&) if you need to modify the passed object.
  • Use f(X&&) if you need to own the passed object.

 

Multiple Move constructors:

A move constructor of class T is a non-template constructor whose first parameter is T&&, const T&&, volatile T&&, or const volatile T&&, and either there are no other parameters, or the rest of the parameters all have default values.

but const T&& in move constructor does not make much sense, the reason are:

The rvalue references don’t make sense in their const forms because you want to modify them (you want to “move” them ). Objects created as const in C++ are in read-only memory, from which grabbing/modifying internal resources won’t be possible.

So A move constructor should normally take a non-const reference


Some constructor are deleted implicitly!Deleted implicitly-declared move constructor

The implicitly-declared or defaulted move constructor for class T is defined as deleted in any of the following is true:

  • T has non-static data members that cannot be moved (have deleted, inaccessible, or ambiguous move constructors);
  • T has direct or virtual base class that cannot be moved (has deleted, inaccessible, or ambiguous move constructors);
  • T has direct or virtual base class with a deleted or inaccessible destructor;
  • T is a union and has a variant member with non-trivial copy constructor;
  • T has a non-static data member or a direct or virtual base without a move constructor that is not trivially copyable.
(until C++14)
The deleted implicitly-declared move constructor is ignored by overload resolution (otherwise it would prevent copy-initialization from rvalue). (since C++14)

 

 References:

http://en.cppreference.com/w/cpp/language/copy_constructor

http://en.cppreference.com/w/cpp/language/rule_of_three

https://bytes.com/topic/c/answers/129603-multiple-copy-constructors

http://stackoverflow.com/questions/5503352/const-before-or-const-after

http://en.cppreference.com/w/cpp/language/move_constructor

http://stackoverflow.com/questions/10770181/should-a-move-constructor-take-a-const-or-non-const-rvalue-reference

Please rate this


Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>