Namespaces
Variants
Views
Actions

Assignment operators

From cppreference.com
< cpp‎ | language
 
 
C++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++17*)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
explicit (C++11)
static

Special member functions
Templates
Miscellaneous
 
 

Assignment operators modify the value of the object.

Operator name  Syntax  Over​load​able Prototype examples (for class T)
Inside class definition Outside class definition
simple assignment a = b Yes T& T::operator =(const T2& b); N/A
addition assignment a += b Yes T& T::operator +=(const T2& b); T& operator +=(T& a, const T2& b);
subtraction assignment a -= b Yes T& T::operator -=(const T2& b); T& operator -=(T& a, const T2& b);
multiplication assignment a *= b Yes T& T::operator *=(const T2& b); T& operator *=(T& a, const T2& b);
division assignment a /= b Yes T& T::operator /=(const T2& b); T& operator /=(T& a, const T2& b);
remainder assignment a %= b Yes T& T::operator %=(const T2& b); T& operator %=(T& a, const T2& b);
bitwise AND assignment a &= b Yes T& T::operator &=(const T2& b); T& operator &=(T& a, const T2& b);
bitwise OR assignment a |= b Yes T& T::operator |=(const T2& b); T& operator |=(T& a, const T2& b);
bitwise XOR assignment a ^= b Yes T& T::operator ^=(const T2& b); T& operator ^=(T& a, const T2& b);
bitwise left shift assignment a <<= b Yes T& T::operator <<=(const T2& b); T& operator <<=(T& a, const T2& b);
bitwise right shift assignment a >>= b Yes T& T::operator >>=(const T2& b); T& operator >>=(T& a, const T2& b);
Notes
  • All built-in assignment operators return *this, and most user-defined overloads also return *this so that the user-defined operators can be used in the same manner as the built-ins. However, in a user-defined operator overload, any type can be used as return type (including void).
  • T2 can be any type including T.

Contents

[edit] Definitions

Copy assignment replaces the contents of the object a with a copy of the contents of b (b is not modified). For class types, this is performed in a special member function, described in copy assignment operator.

Move assignment replaces the contents of the object a with the contents of b, avoiding copying if possible (b may be modified). For class types, this is performed in a special member function, described in move assignment operator.

(since C++11)

For non-class types, copy and move assignment are indistinguishable and are referred to as direct assignment.

Compound assignment replace the contents of the object a with the result of a binary operation between the previous value of a and the value of b.

[edit] Assignment operator syntax

The assignment expressions have the form

target-expr = new-value (1)
target-expr op new-value (2)
target-expr - the expression[1] to be assigned to
op - one of *=, /= %=, += -=, <<=, >>=, &=, ^=, |=
new-value - the expression[2](until C++11)initializer clause(since C++11) to assign to the target
  1. target-expr must have higher precedence than an assignment expression.
  2. new-value cannot be a comma expression, because its precedence is lower.
1) Simple assignment expression.
2) Compound assignment expression.

If new-value is not an expression, the assignment expression will never match an overloaded compound assignment operator.

(since C++11)

[edit] Built-in simple assignment operator

For the built-in simple assignment, the object referred to by target-expr is modified by replacing its value with the result of new-value. target-expr must be a modifiable lvalue.

The result of a built-in simple assignment is an lvalue of the type of target-expr, referring to target-expr. If target-expr is a bit-field, the result is also a bit-field.

[edit] Assignment from an expression

If new-value is an expression, it is implicitly converted to the cv-unqualified type of target-expr. When target-expr is a bit-field that cannot represent the value of the expression, the resulting value of the bit-field is implementation-defined.

If target-expr and new-value identify overlapping objects, the behavior is undefined (unless the overlap is exact and the type is the same).

If the type of target-expr is volatile-qualified, the assignment is deprecated, unless the (possibly parenthesized) assignment expression is a discarded-value expression or an unevaluated operand.

(since C++20)


Assignment from a non-expression initializer clause

new-value is only allowed not to be an expression in following situations:

  • target-expr is of a scalar type T, and new-value is empty or has only one element. In this case, given an invented variable t declared and initialized as T t = new-value , the meaning of x = new-value  is x = t.
  • target-expr is of class type. In this case, new-value is passed as the argument to the assignment operator function selected by overload resolution.
#include <complex>
 
std::complex<double> z;
z = {1, 2};  // meaning z.operator=({1, 2})
z += {1, 2}; // meaning z.operator+=({1, 2})
 
int a, b;
a = b = {1}; // meaning a = b = 1;
a = {1} = b; // syntax error
(since C++11)

In overload resolution against user-defined operators, for every type T, the following function signatures participate in overload resolution:

T*& operator=(T*&, T*);
T*volatile & operator=(T*volatile &, T*);

For every enumeration or pointer to member type T, optionally volatile-qualified, the following function signature participates in overload resolution:

T& operator=(T&, T);

For every pair A1 and A2, where A1 is an arithmetic type (optionally volatile-qualified) and A2 is a promoted arithmetic type, the following function signature participates in overload resolution:

A1& operator=(A1&, A2);

[edit] Built-in compound assignment operator

The behavior of every built-in compound-assignment expression target-expr op = new-value is exactly the same as the behavior of the expression target-expr = target-expr op new-value, except that target-expr is evaluated only once.

The requirements on target-expr and new-value of built-in simple assignment operators also apply. Furthermore:

  • For += and -=, the type of target-expr must be an arithmetic type or a pointer to a (possibly cv-qualified) completely-defined object type.
  • For all other compound assignment operators, the type of target-expr must be an arithmetic type.

In overload resolution against user-defined operators, for every pair A1 and A2, where A1 is an arithmetic type (optionally volatile-qualified) and A2 is a promoted arithmetic type, the following function signatures participate in overload resolution:

A1& operator*=(A1&, A2);
A1& operator/=(A1&, A2);
A1& operator+=(A1&, A2);
A1& operator-=(A1&, A2);

For every pair I1 and I2, where I1 is an integral type (optionally volatile-qualified) and I2 is a promoted integral type, the following function signatures participate in overload resolution:

I1& operator%=(I1&, I2);
I1& operator<<=(I1&, I2);
I1& operator>>=(I1&, I2);
I1& operator&=(I1&, I2);
I1& operator^=(I1&, I2);
I1& operator|=(I1&, I2);

For every optionally cv-qualified object type T, the following function signatures participate in overload resolution:

T*& operator+=(T*&, std::ptrdiff_t);
T*& operator-=(T*&, std::ptrdiff_t);
T*volatile & operator+=(T*volatile &, std::ptrdiff_t);
T*volatile & operator-=(T*volatile &, std::ptrdiff_t);

[edit] Example

#include <iostream>
 
int main()
{
    int n = 0;        // not an assignment
 
    n = 1;            // direct assignment
    std::cout << n << ' ';
 
    n = {};           // zero-initialization, then assignment
    std::cout << n << ' ';
 
    n = 'a';          // integral promotion, then assignment
    std::cout << n << ' ';
 
    n = {'b'};        // explicit cast, then assignment
    std::cout << n << ' ';
 
    n = 1.0;          // floating-point conversion, then assignment
    std::cout << n << ' ';
 
//  n = {1.0};        // compiler error (narrowing conversion)
 
    int& r = n;       // not an assignment
    r = 2;            // assignment through reference
    std::cout << n << ' ';
 
    int* p;
    p = &n;           // direct assignment
    p = nullptr;      // null-pointer conversion, then assignment
    std::cout << p << ' ';
 
    struct { int a; std::string s; } obj;
    obj = {1, "abc"}; // assignment from a braced-init-list
    std::cout << obj.a << ':' << obj.s << '\n';
}

Possible output:

1 0 97 98 1 2 (nil) 1:abc

[edit] Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 1527 C++11 for assignments to class type objects, the right operand
could be an initializer list only when the assignment
is defined by a user-defined assignment operator
removed user-defined
assignment constraint
CWG 1538 C++11 E1 = {E2} was equivalent to E1 = T(E2)
(T is the type of E1), this introduced a C-style cast
it is equivalent
to E1 = T{E2}
CWG 2654 C++20 compound assignment operators for volatile
-qualified types were inconsistently deprecated
none of them
is deprecated
CWG 2768 C++11 an assignment from a non-expression initializer clause
to a scalar value would perform direct-list-initialization
performs copy-list-
initialization instead
P2327R1 C++20 bitwise compound assignment operators for volatile types
were deprecated while being useful for some platforms
they are not
deprecated

[edit] See also

Operator precedence

Operator overloading

Common operators
assignment increment
decrement
arithmetic logical comparison member
access
other

a = b
a += b
a -= b
a *= b
a /= b
a %= b
a &= b
a |= b
a ^= b
a <<= b
a >>= b

++a
--a
a++
a--

+a
-a
a + b
a - b
a * b
a / b
a % b
~a
a & b
a | b
a ^ b
a << b
a >> b

!a
a && b
a || b

a == b
a != b
a < b
a > b
a <= b
a >= b
a <=> b

a[...]
*a
&a
a->b
a.b
a->*b
a.*b

function call
a(...)
comma
a, b
conditional
a ? b : c
Special operators

static_cast converts one type to another related type
dynamic_cast converts within inheritance hierarchies
const_cast adds or removes cv-qualifiers
reinterpret_cast converts type to unrelated type
C-style cast converts one type to another by a mix of static_cast, const_cast, and reinterpret_cast
new creates objects with dynamic storage duration
delete destructs objects previously created by the new expression and releases obtained memory area
sizeof queries the size of a type
sizeof... queries the size of a parameter pack (since C++11)
typeid queries the type information of a type
noexcept checks if an expression can throw an exception (since C++11)
alignof queries alignment requirements of a type (since C++11)

C documentation for Assignment operators