12 Special member functions [special]

12.8 Copying and moving class objects [class.copy]

A class object can be copied or moved in two ways: by initialization ([class.ctor], [dcl.init]), including for function argument passing ([expr.call]) and for function value return ([stmt.return]); and by assignment ([expr.ass]). Conceptually, these two operations are implemented by a copy/move constructor ([class.ctor]) and copy/move assignment operator ([over.ass]).

A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments ([dcl.fct.default]). [ Example: X::X(const X&) and X::X(X&,int=1) are copy constructors.

struct X {
  X(int);
  X(const X&, int = 1);
};
X a(1);             // calls X(int);
X b(a, 0);          // calls X(const X&, int);
X c = b;            // calls X(const X&, int);

 — end example ]

A non-template constructor for class X is a move constructor if its first parameter is of type X&&, const X&&, volatile X&&, or const volatile X&&, and either there are no other parameters or else all other parameters have default arguments ([dcl.fct.default]). [ Example: Y::Y(Y&&) is a move constructor.

struct Y {
  Y(const Y&);
  Y(Y&&);
};
extern Y f(int);
Y d(f(1));          // calls Y(Y&&)
Y e = d;            // calls Y(const Y&)

 — end example ]

Note: All forms of copy/move constructor may be declared for a class. [ Example:

struct X {
  X(const X&);
  X(X&);            // OK
  X(X&&);
  X(const X&&);     // OK, but possibly not sensible
};

 — end example ]  — end note ]

Note: If a class X only has a copy constructor with a parameter of type X&, an initializer of type const X or volatile X cannot initialize an object of type (possibly cv-qualified) X. [ Example:

struct X {
  X();              // default constructor
  X(X&);            // copy constructor with a nonconst parameter
};
const X cx;
X x = cx;           // error: X::X(X&) cannot copy cx into x

 — end example ]  — end note ]

A declaration of a constructor for a class X is ill-formed if its first parameter is of type (optionally cv-qualified) X and either there are no other parameters or else all other parameters have default arguments. A member function template is never instantiated to produce such a constructor signature. [ Example:

struct S {
  template<typename T> S(T);
  S();
};

S g;

void h() {
  S a(g);           // does not instantiate the member template to produce S::S<S>(S);
                    // uses the implicitly declared copy constructor
}

 — end example ]

If the class definition does not explicitly declare a copy constructor, 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 ([dcl.fct.def]). The latter case is deprecated if the class has a user-declared copy assignment operator or a user-declared destructor. Thus, for the class definition

struct X {
  X(const X&, int);
};

a copy constructor is implicitly-declared. If the user-declared constructor is later defined as

X::X(const X& x, int i =0) { /* ... */ }

then any use of X's copy constructor is ill-formed because of the ambiguity; no diagnostic is required.

The implicitly-declared copy constructor for a class X will have the form

X::X(const X&)

if

  • each direct or virtual base class B of X has a copy constructor whose first parameter is of type const B& or const volatile B&, and

  • for all the non-static data members of X that are of a class type M (or array thereof), each such class type has a copy constructor whose first parameter is of type const M& or const volatile M&.119

Otherwise, the implicitly-declared copy constructor will have the form

X::X(X&)

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,

  • X does not have a user-declared destructor, and

  • the move constructor would not be implicitly defined as deleted.

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 ]

The implicitly-declared move constructor for class X will have the form

X::X(X&&)

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 ([dcl.fct.def.delete]) 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 ([over.match]), 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 ([over.match]), 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,

  • for the copy constructor, a non-static data member of rvalue reference type, or

  • for the move constructor, a non-static data member or direct or virtual base class with a type that does not have a move constructor and is not trivially copyable.

A copy/move constructor for class X is trivial if it is not user-provided and if

  • class X has no virtual functions ([class.virtual]) and no virtual base classes ([class.mi]), and

  • the constructor selected to copy/move each direct base class subobject is trivial, and

  • for each non-static data member of X that is of class type (or array thereof), the constructor selected to copy/move that member is trivial;

otherwise the copy/move constructor is non-trivial.

A copy/move constructor that is defaulted and not defined as deleted is implicitly defined if it is odr-used ([basic.def.odr]) to initialize an object of its class type from a copy of an object of its class type or of a class type derived from its class type120 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 ([basic.def.odr], [class.temporary]).  — end note ] If the implicitly-defined constructor would satisfy the requirements of a constexpr constructor ([dcl.constexpr]), the implicitly-defined constructor is constexpr.

Before the defaulted copy/move constructor for a class is implicitly defined, all non-user-provided copy/move constructors for its direct and virtual base classes and its non-static data members shall have been implicitly defined. [ Note: An implicitly-declared copy/move constructor has an exception-specification ([except.spec]).  — end note ]

The implicitly-defined copy/move constructor for 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 [class.base.init].  — end note ] The order of initialization is the same as the order of initialization of bases and members in a user-defined constructor (see [class.base.init]). 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<T&&>(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 [class.base.init]).

The implicitly-defined copy/move constructor for a union X copies the object representation ([basic.types]) of X.

A user-declared copy assignment operator X::operator= is a non-static non-template member function of class X with exactly one parameter of type X, X&, const X&, volatile X& or const volatile X&.121Note: An overloaded assignment operator must be declared to have only one parameter; see [over.ass].  — end note ] [ Note: More than one form of copy assignment operator may be declared for a class.  — end note ] [ Note: If a class X only has a copy assignment operator with a parameter of type X&, an expression of type const X cannot be assigned to an object of type X. [ Example:

struct X {
  X();
  X& operator=(X&);
};
const X cx;
X x;
void f() {
  x = cx;           // error: X::operator=(X&) cannot assign cx into x
}

 — end example ]  — end note ]

If the class definition does not explicitly declare a copy assignment operator, one is declared implicitly. If the class definition declares a move constructor or move assignment operator, the implicitly declared copy assignment operator is defined as deleted; otherwise, it is defined as defaulted ([dcl.fct.def]). The latter case is deprecated if the class has a user-declared copy constructor or a user-declared destructor. The implicitly-declared copy assignment operator for a class X will have the form

X& X::operator=(const X&)

if

  • each direct base class B of X has a copy assignment operator whose parameter is of type const B&, const volatile B& or B, and

  • for all the non-static data members of X that are of a class type M (or array thereof), each such class type has a copy assignment operator whose parameter is of type const M&, const volatile M& or M.122

Otherwise, the implicitly-declared copy assignment operator will have the form

X& X::operator=(X&)

A user-declared move assignment operator X::operator= is a non-static non-template member function of class X with exactly one parameter of type X&&, const X&&, volatile X&&, or const volatile X&&. [ Note: An overloaded assignment operator must be declared to have only one parameter; see [over.ass].  — end note ] [ Note: More than one form of move assignment operator may be declared for a class.  — end note ]

If the definition of a class X does not explicitly declare a move assignment operator, 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 move constructor,

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

  • X does not have a user-declared destructor, and

  • the move assignment operator would not be implicitly defined as deleted.

Example: The class definition

struct S {
  int a;
  S& operator=(const S&) = default;
};

will not have a default move assignment operator implicitly declared because the copy assignment operator has been user-declared. The move assignment operator may be explicitly defaulted.

struct S {
  int a;
  S& operator=(const S&) = default;
  S& operator=(S&&) = default;
};

 — end example ]

The implicitly-declared move assignment operator for a class X will have the form

X& X::operator=(X&&);

The implicitly-declared copy/move assignment operator for class X has the return type X&; it returns the object for which the assignment operator is invoked, that is, the object assigned to. An implicitly-declared copy/move assignment operator is an inline public member of its class.

A defaulted copy/move assignment operator for class X is defined as deleted if X has:

  • a variant member with a non-trivial corresponding assignment operator and X is a union-like class, or

  • a non-static data member of const non-class type (or array thereof), or

  • a non-static data member of reference type, or

  • a non-static data member of class type M (or array thereof) that cannot be copied/moved because overload resolution ([over.match]), as applied to M's corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator, or

  • a direct or virtual base class B that cannot be copied/moved because overload resolution ([over.match]), as applied to B's corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator, or

  • for the move assignment operator, a non-static data member or direct base class with a type that does not have a move assignment operator and is not trivially copyable, or any direct or indirect virtual base class.

Because a copy/move assignment operator is implicitly declared for a class if not declared by the user, a base class copy/move assignment operator is always hidden by the corresponding assignment operator of a derived class ([over.ass]). A using-declaration ([namespace.udecl]) that brings in from a base class an assignment operator with a parameter type that could be that of a copy/move assignment operator for the derived class is not considered an explicit declaration of such an operator and does not suppress the implicit declaration of the derived class operator; the operator introduced by the using-declaration is hidden by the implicitly-declared operator in the derived class.

A copy/move assignment operator for class X is trivial if it is not user-provided and if

  • class X has no virtual functions ([class.virtual]) and no virtual base classes ([class.mi]), and

  • the assignment operator selected to copy/move each direct base class subobject is trivial, and

  • for each non-static data member of X that is of class type (or array thereof), the assignment operator selected to copy/move that member is trivial;

otherwise the copy/move assignment operator is non-trivial.

A copy/move assignment operator that is defaulted and not defined as deleted is implicitly defined when it is odr-used ([basic.def.odr]) (e.g., when it is selected by overload resolution to assign to an object of its class type) or when it is explicitly defaulted after its first declaration.

Before the defaulted copy/move assignment operator for a class is implicitly defined, all non-user-provided copy/move assignment operators for its direct base classes and its non-static data members shall have been implicitly defined. [ Note: An implicitly-declared copy/move assignment operator has an exception-specification ([except.spec]).  — end note ]

The implicitly-defined copy/move assignment operator for a non-union class X performs memberwise copy/move assignment of its subobjects. The direct base classes of X are assigned first, in the order of their declaration in the base-specifier-list, and then the immediate non-static data members of X are assigned, in the order in which they were declared in the class definition. Let x be either the parameter of the function or, for the move operator, an xvalue referring to the parameter. Each subobject is assigned in the manner appropriate to its type:

  • if the subobject is of class type, as if by a call to operator= with the subobject as the object expression and the corresponding subobject of x as a single function argument (as if by explicit qualification; that is, ignoring any possible virtual overriding functions in more derived classes);

  • if the subobject is an array, each element is assigned, in the manner appropriate to the element type;

  • if the subobject is of scalar type, the built-in assignment operator is used.

It is unspecified whether subobjects representing virtual base classes are assigned more than once by the implicitly-defined copy assignment operator. [ Example:

struct V { };
struct A : virtual V { };
struct B : virtual V { };
struct C : B, A { };

It is unspecified whether the virtual base class subobject V is assigned twice by the implicitly-defined copy assignment operator for C.  — end example ] [ Note: This does not apply to move assignment, as a defaulted move assignment operator is deleted if the class has virtual bases.  — end note ]

The implicitly-defined copy assignment operator for a union X copies the object representation ([basic.types]) of X.

A program is ill-formed if the copy/move constructor or the copy/move assignment operator for an object is implicitly odr-used and the special member function is not accessible (Clause [class.access]). [ Note: Copying/moving one object into another using the copy/move constructor or the copy/move assignment operator does not change the layout or size of either object.  — end note ]

When certain criteria are met, an implementation is allowed to omit the copy/move construction of a class object, even if the copy/move constructor and/or destructor for the object have side effects. In such cases, the implementation treats the source and target of the omitted copy/move operation as simply two different ways of referring to the same object, and the destruction of that object occurs at the later of the times when the two objects would have been destroyed without the optimization.123 This elision of copy/move operations, called copy elision, is permitted in the following circumstances (which may be combined to eliminate multiple copies):

  • in a return statement in a function with a class return type, when the expression is the name of a non-volatile automatic object (other than a function or catch-clause parameter) with the same cv-unqualified type as the function return type, the copy/move operation can be omitted by constructing the automatic object directly into the function's return value

  • in a throw-expression, when the operand is the name of a non-volatile automatic object (other than a function or catch-clause parameter) whose scope does not extend beyond the end of the innermost enclosing try-block (if there is one), the copy/move operation from the operand to the exception object ([except.throw]) can be omitted by constructing the automatic object directly into the exception object

  • when a temporary class object that has not been bound to a reference ([class.temporary]) would be copied/moved to a class object with the same cv-unqualified type, the copy/move operation can be omitted by constructing the temporary object directly into the target of the omitted copy/move

  • when the exception-declaration of an exception handler (Clause [except]) declares an object of the same type (except for cv-qualification) as the exception object ([except.throw]), the copy/move operation can be omitted by treating the exception-declaration as an alias for the exception object if the meaning of the program will be unchanged except for the execution of constructors and destructors for the object declared by the exception-declaration.

Example:

class Thing {
public:
  Thing();
  ~Thing();
  Thing(const Thing&);
};

Thing f() {
  Thing t;
  return t;
}

Thing t2 = f();

Here the criteria for elision can be combined to eliminate two calls to the copy constructor of class Thing: the copying of the local automatic object t into the temporary object for the return value of function f() and the copying of that temporary object into object t2. Effectively, the construction of the local object t can be viewed as directly initializing the global object t2, and that object's destruction will occur at program exit. Adding a move constructor to Thing has the same effect, but it is the move construction from the temporary object to t2 that is elided.  — end example ]

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If overload resolution fails, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue. [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided.  — end note ]

Example:

class Thing {
public:
  Thing();
  ~Thing();
  Thing(Thing&&);
private:
  Thing(const Thing&);
};

Thing f(bool b) {
  Thing t;
  if (b)
    throw t;                    // OK: Thing(Thing&&) used (or elided) to throw t
  return t;                     // OK: Thing(Thing&&) used (or elided) to return t
}

Thing t2 = f(false);            // OK: Thing(Thing&&) used (or elided) to construct t2

 — end example ]

This implies that the reference parameter of the implicitly-declared copy constructor cannot bind to a volatile lvalue; see [diff.special].

See [dcl.init] for more details on direct and copy initialization.

Because a template assignment operator or an assignment operator taking an rvalue reference parameter is never a copy assignment operator, the presence of such an assignment operator does not suppress the implicit declaration of a copy assignment operator. Such assignment operators participate in overload resolution with other assignment operators, including copy assignment operators, and, if selected, will be used to assign an object.

This implies that the reference parameter of the implicitly-declared copy assignment operator cannot bind to a volatile lvalue; see [diff.special].

Because only one object is destroyed instead of two, and one copy/move constructor is not executed, there is still one object destroyed for each one constructed.