11 Classes [class]

11.4 Class members [class.mem]

11.4.6 Copy/move assignment operator [class.copy.assign]

A user-declared copy assignment operator X​::​operator= is a non-static non-template member function of class X with exactly one non-object parameter of type X, X&, const X&, volatile X&, or const volatile X&.95
[Note 1: 
An overloaded assignment operator must be declared to have only one parameter; see [over.ass].
— end note]
[Note 2: 
More than one form of copy assignment operator can be declared for a class.
— end note]
[Note 3: 
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 1: 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 defaulted ([dcl.fct.def]).
The latter case is deprecated if the class has a user-declared copy constructor or a user-declared destructor ([depr.impldec]).
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.96
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 non-object parameter of type X&&, const X&&, volatile X&&, or const volatile X&&.
[Note 4: 
An overloaded assignment operator must be declared to have only one parameter; see [over.ass].
— end note]
[Note 5: 
More than one form of move assignment operator can 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, and
  • X does not have a user-declared destructor.
[Example 2: 
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&.
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 direct non-static data member of class type M (or array thereof) or a direct base class M that cannot be copied/moved because overload resolution ([over.match]), as applied to find M's corresponding assignment operator, results in an ambiguity or a function that is deleted or inaccessible from the defaulted assignment operator.
[Note 6: 
A defaulted move assignment operator that is defined as deleted is ignored by overload resolution ([over.match], [over.over]).
— end note]
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]).
[Note 7: 
A using-declaration in a derived class C that names an assignment operator from a base class never suppresses the implicit declaration of an assignment operator of C, even if the base class assignment operator would be a copy or move assignment operator if declared as a member of C.
— end note]
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.
An implicitly-defined ([dcl.fct.def.default]) copy/move assignment operator is constexpr.
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 are implicitly defined.
[Note 8: 
An implicitly-declared copy/move assignment operator has an implied 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/move assignment operator.
[Example 3: 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/move assignment operator for C.
— end example]
The implicitly-defined copy/move assignment operator for a union X copies the object representation ([basic.types.general]) of X.
If the source and destination of the assignment are not the same object, then for each object nested within ([intro.object]) the object that is the source of the copy, a corresponding object o nested within the destination is created, and the lifetime of o begins before the copy is performed.
The implicitly-defined copy/move assignment operator for a class returns the object for which the assignment operator is invoked, that is, the object assigned to.
95)95)
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.
96)96)
This implies that the reference parameter of the implicitly-declared copy assignment operator cannot bind to a volatile lvalue; see [diff.class].