Conditions For Automatic Generation of Default/Copy/Move Ctor and Copy/Move Assignment Operator

Conditions for automatic generation of default/copy/move ctor and copy/move assignment operator?

In the following, "auto-generated" means "implicitly declared as defaulted, but not defined as deleted". There are situations where the special member functions are declared, but defined as deleted.

  • The default constructor is auto-generated if there is no user-declared constructor (§12.1/5).
  • The copy constructor is auto-generated if there is no user-declared move constructor or move assignment operator (because there are no move constructors or move assignment operators in C++03, this simplifies to "always" in C++03) (§12.8/8).
  • The copy assignment operator is auto-generated if there is no user-declared move constructor or move assignment operator (§12.8/19).
  • The destructor is auto-generated if there is no user-declared destructor (§12.4/4).

C++11 and later only:

  • The move constructor is auto-generated if there is no user-declared copy constructor, copy assignment operator or destructor, and if the generated move constructor is valid (§12.8/10).
  • The move assignment operator is auto-generated if there is no user-declared copy constructor, copy assignment operator or destructor, and if the generated move assignment operator is valid (e.g. if it wouldn't need to assign constant members) (§12.8/21).

What are the rules for automatic generation of move operations?

From the standard Ch. 12 - Special member functions

Par 12.8 Copying and moving class objects (emphasis mine)

9 . If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if

— X does not have a user-declared copy constructor,

— X does not have a user-declared copy assignment operator,

— X does not have a user-declared move assignment operator, and

— X does not have a user-declared destructor.

[ Note: When the move constructor is not implicitly declared or explicitly supplied, expressions that
otherwise would have invoked the move constructor may instead invoke a copy constructor. —end note ]

Then 11 explains the rules for deleting the defaulted move constructor

11 . An implicitly-declared copy/move constructor is an inline public member of its class. A defaulted copy/ move constructor for a class X is defined as deleted (8.4.3) if X has:

— a variant member with a non-trivial corresponding constructor and X is a union-like class,

— a non-static data member of class type M (or array thereof) that cannot be copied/moved because overload resolution (13.3), as applied to M’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor,

— a direct or virtual base class B that cannot be copied/moved because overload resolution (13.3), as applied to B’s corresponding constructor, results in an ambiguity or a function that is deleted or inaccessible from the defaulted constructor,

— any direct or virtual base class or non-static data member of a type with a destructor that is deleted or inaccessible from the defaulted constructor, or,

— for the copy constructor, a non-static data member of rvalue reference type. A defaulted move constructor that is defined as deleted is ignored by overload resolution (13.3, 13.4).

[ Note: A deleted move constructor would otherwise interfere with initialization from an rvalue which can use the copy constructor instead. —end note ]



On the complexity of it all *

The rules can be somewhat overwhelming. It's good to use some technique to bypass the complexity. Examples are :

  1. Make use of the rule of zero to simplify the writing of the majority of your classes.
  2. (On implicitly deleted) Explicitly default the special member function in question; if it would have been implicitly defined as deleted, the compiler will complain.

* points made in the comments by myself (1) and dyp (2)

c++ move constructor generated with default constructor

It is nothing related to the move constructor It is about the default constructor. Try this:

class Y
{
public:
Y(const Y&) {}
};

struct hasY {
hasY() = default;
hasY(hasY&&) = default;
Y mem;
};
hasY hy; // This will cause an error because there is no default constructor

Now if you add the default constructor: Y(){}, the error will go away.


As @M.M commented, The copy constructor will be called in a such case.

You may try this code:

class Y{
public:
Y(){std::cout << "Default constructor\n";}
Y(const Y&) {std::cout << "Copy constructor\n";}
};

struct hasY {
hasY() = default;
hasY(hasY&&) = default;
Y mem;
};

int main(){
hasY hy;
hasY h=std::move(hy);
}

It will print:

Default constructor

Copy constructor

If you want to make the class not moveable you should delete the move constructor by yourself Y(Y&&)=delete;

Conditions under which compiler will not define implicits (constructor, destructor, copy constructor, copy assignment) [duplicate]

The Default Constuctor (e.g., X()) will not be implicitly generated if:

  • you have explicitly declared any constructor at all
  • there is a data member that is not default-constructible (such as a reference, a const object, or a class with no or inaccessible default constructor)
  • (C++11) you have explicitly told the compiler to not generate one using X() = delete;

The Copy Constructor (e.g., X(const X&)) will not be implicitly generated if:

  • you have explicitly declared a copy constructor (for class X a constructor taking X, X& or const X&)
  • there is a data member that is not copy-constructible (such as a class with no or inaccessible copy constructor)
  • the base class is not copy-constructible
  • (C++11) you have declared a move constructor or move assignment operator
  • (C++11) you have explicitly told the compiler to not generate one using X(const X&) = delete;

The Copy Assignment Operator (e.g., X& operator=(const X&)) will not be implicitly generated if:

  • you have explicitly declared a copy assignment operator (for class X an operator= taking X, X& or const X&)
  • there is a data member in your class that is not copy-assignable (such as a reference, a const object, or a class with no or inaccessible assignment operator)
  • the base class is not copy-assignable
  • (C++11) you have declared a move constructor or move assignment operator
  • (C++11) you have explicitly told the compiler to not generate one using X& operator=(const X&) = delete;

The Destructor (e.g., ~X()) will not be implicitly generated if:

  • you have explicitly declared a destructor
  • (C++11) you have explicitly told the compiler to not generate one using ~X() = delete;

The Move Constructor (C++11) (e.g., X(X&&)) will not be implicitly generated if:

  • you have explicitly declared a move constructor (for class X, a constructor taking X&&)
  • you have declared a copy assignment operator, copy constructor, destructor, or move assignment operator
  • there is a data member in your class that cannot be move-constructed (is const, is a reference, or has a deleted, inaccessible, or ambiguous move constructor)
  • the base class cannot be move-constructed
  • you have explicitly told the compiler to not generate one using X(X&&) = delete;

The Move Assignment Operator (C++11) (e.g., X& operator=(X&&)) will not be implicitly generated if:

  • you have explicitly declared a move assignment operator (for class X, an operator= taking X&&)
  • you have declared a copy assignment operator, copy constructor, destructor, or move constructor
  • there is a data member in your class that cannot be move-assigned (is const, is a reference, or has a deleted, inaccessible, or ambiguous move assignment operator)
  • the base class cannot be move-assigned
  • you have explicitly told the compiler to not generate one using X& operator=(X&&) = delete;

operator + need Move Constructors

A elision optimisation is permitted here (NRVO) but the object must still be semantically copyable/moveable; by deleting the move constructor, you also deleted the copy constructor, so neither operation is valid and the program is ill-formed.

You can add the copy ctor back:

poo(const poo&) = default;

(And, even if you were using C++17, its guaranteed elision doesn't apply to lvalues.)

Implicit copy constructor in presence of user-defined move constructor/assignment [duplicate]

At least as of the draft I have handiest at the moment (N4618), it's at §[class.copy.ctor]/6:

If the class definition does not explicitly declare a copy constructor, a non-explicit one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4).



Related Topics



Leave a reply



Submit