Namespaces
Variants

Assignment operators

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
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
Special member functions
Templates
Miscellaneous

Операторы присваивания изменяют значение объекта.

Название оператора Синтаксис Перегружаемый Примеры прототипов (для class T )
Внутри определения класса Вне определения класса
простое присваивание a = b Да T & T :: operator = ( const T2 & b ) ; Н/П
оператор присваивания сложения a += b Да T & T :: operator + = ( const T2 & b ) ; T & operator + = ( T & a, const T2 & b ) ;
оператор вычитания с присваиванием a -= b Да T & T :: operator - = ( const T2 & b ) ; T & operator - = ( T & a, const T2 & b ) ;
оператор умножения с присваиванием a *= b Да T & T :: operator * = ( const T2 & b ) ; T & operator * = ( T & a, const T2 & b ) ;
операция деления с присваиванием a /= b Да T & T :: operator / = ( const T2 & b ) ; T & operator / = ( T & a, const T2 & b ) ;
оператор присваивания остатка a %= b Да T & T :: operator % = ( const T2 & b ) ; T & operator % = ( T & a, const T2 & b ) ;
Побитовое И присваивание a &= b Да T & T :: operator & = ( const T2 & b ) ; T & operator & = ( T & a, const T2 & b ) ;
побитовое ИЛИ присваивание a |= b Да T & T :: operator | = ( const T2 & b ) ; T & operator | = ( T & a, const T2 & b ) ;
Побитовое исключающее ИЛИ с присваиванием a ^= b Да T & T :: operator ^ = ( const T2 & b ) ; T & operator ^ = ( T & a, const T2 & b ) ;
побитовый сдвиг влево с присваиванием a <<= b Да T & T :: operator <<= ( const T2 & b ) ; T & operator <<= ( T & a, const T2 & b ) ;
побитовый сдвиг вправо с присваиванием a >>= b Да T & T :: operator >>= ( const T2 & b ) ; T & operator >>= ( T & a, const T2 & b ) ;
Примечания
  • Все встроенные операторы присваивания возвращают * this , и большинство пользовательских перегрузок также возвращают * this , чтобы пользовательские операторы могли использоваться так же, как встроенные. Однако в пользовательской перегрузке оператора может использоваться любой тип в качестве возвращаемого значения (включая void ).
  • T2 может быть любым типом, включая T .

Содержание

Определения

Копирующее присваивание заменяет содержимое объекта a копией содержимого b ( b не изменяется). Для классовых типов это выполняется специальной функцией-членом, описанной в операторе копирующего присваивания .

Перемещающее присваивание заменяет содержимое объекта a содержимым объекта b , избегая копирования, если это возможно ( b может быть изменён). Для типов классов это выполняется специальной функцией-членом, описанной в операторе перемещающего присваивания .

(начиная с C++11)

Для неклассовых типов копирующее и перемещающее присваивание неразличимы и называются прямым присваиванием .

Составное присваивание заменяет содержимое объекта a результатом бинарной операции между предыдущим значением a и значением b .

Синтаксис оператора присваивания

Выражения присваивания имеют вид

target-expr = new-value (1)
target-expr op new-value (2)
target-expr - выражение [1] для присваивания
op - один из операторов * = , / = % = , + = - = , <<= , >>= , & = , ^ = , | =
new-value - выражение [2] (до C++11) инициализирующее выражение (начиная с C++11) для присваивания цели
  1. target-expr должен иметь более высокий приоритет чем выражение присваивания.
  2. new-value не может быть выражением с запятой, поскольку его приоритет ниже.
1) Простое выражение присваивания.
2) Составное выражение присваивания.

Если new-value не является выражением, оператор присваивания никогда не будет соответствовать перегруженному составному оператору присваивания.

(since C++11)

Встроенный оператор простого присваивания

Для встроенного простого присваивания target-expr должен быть изменяемым lvalue.

Объект, на который ссылается target-expr , модифицируется путем замены его значения на результат new-value . Если на который ссылается объект имеет целочисленный тип T , и результат new-value имеет соответствующий знаковый/беззнаковый целочисленный тип, значение объекта заменяется значением типа T с тем же представлением значения результата new-value .

Результатом встроенного простого присваивания является lvalue типа target-expr , ссылающееся на target-expr . Если target-expr является битовым полем , результат также является битовым полем.

Присваивание из выражения

Если new-value является выражением, оно неявно преобразуется в cv-неквалифицированный тип target-expr . Когда target-expr является битовым полем, которое не может представить значение выражения, результирующее значение битового поля определяется реализацией.

Если target-expr и new-value указывают на перекрывающиеся объекты, поведение не определено (если только перекрытие не является точным и тип не совпадает).

Если тип target-expr является квалифицированным с volatile, присваивание считается устаревшим, если только (возможно, заключённое в скобки) выражение присваивания не является discarded-value expression или unevaluated operand .

(since C++20)


Присваивание из невыражения в виде инициализатора

new-value разрешается не быть выражением только в следующих случаях:

  • target-expr имеет скалярный тип T , и new-value пуст или содержит только один элемент. В этом случае, при введённой переменной t объявленной и инициализированной как T t = new-value  , смысл x = new-value  эквивалентен x = t .
  • target-expr имеет классовый тип. В этом случае new-value передаётся как аргумент в функцию оператора присваивания, выбранную с помощью разрешения перегрузки .
#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
(начиная с C++11)

В разрешении перегрузки для пользовательских операторов , для каждого типа T , следующие сигнатуры функций участвуют в разрешении перегрузки:

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

Для каждого типа перечисления или указателя на член T , опционально с квалификатором volatile, следующая сигнатура функции участвует в разрешении перегрузки:

T & operator = ( T & , T ) ;
**Примечание:** В данном фрагменте кода не содержится переводимого текста - только HTML-разметка и C++ код, который согласно инструкциям не подлежит переводу. Весь представленный контент состоит из: - HTML тегов и атрибутов (сохранены без изменений) - C++ кода внутри тега ` ` (сохранен без изменений) - Специальных символов и операторов C++ Перевод не требуется, так как в тексте отсутствуют естественно-языковые элементы для перевода на русский язык.

Для каждой пары A1 и A2 , где A1 является арифметическим типом (опционально с квалификатором volatile) и A2 является продвинутым арифметическим типом, следующая сигнатура функции участвует в разрешении перегрузки:

A1 & operator = ( A1 & , A2 ) ;

Встроенный составной оператор присваивания

Поведение каждого встроенного составного присваивания target-expr op  = new-value точно такое же, как поведение выражения target-expr = target-expr op new-value , за исключением того, что target-expr вычисляется только один раз.

Требования к target-expr и new-value для встроенных операторов простого присваивания также применяются. Кроме того:

  • Для + = и - = тип target-expr должен быть арифметическим типом или указателем на (возможно cv-квалифицированный) полностью определенный объектный тип .
  • Для всех остальных составных операторов присваивания тип target-expr должен быть арифметическим типом.

В разрешении перегрузки для пользовательских операторов , для каждой пары A1 и A2 , где A1 является арифметическим типом (опционально с volatile-квалификатором) и A2 является продвинутым арифметическим типом, следующие сигнатуры функций участвуют в разрешении перегрузки:

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

Для каждой пары I1 и I2 , где I1 является целочисленным типом (опционально с квалификатором volatile) и I2 является продвинутым целочисленным типом, следующие сигнатуры функций участвуют в разрешении перегрузки:

I1 & operator % = ( I1 & , I2 ) ;
I1 & operator <<= ( I1 & , I2 ) ;
I1 & operator >>= ( I1 & , I2 ) ;
I1 & operator & = ( I1 & , I2 ) ;
I1 & operator ^ = ( I1 & , I2 ) ;
I1 & operator | = ( I1 & , I2 ) ;
**Примечание:** Весь представленный код является C++ кодом внутри тегов ` `, поэтому в соответствии с инструкциями он не был переведен. HTML структура и форматирование полностью сохранены.

Для каждого опционально cv-квалифицированного типа объекта T следующие сигнатуры функций участвуют в разрешении перегрузки:

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 ) ;
**Примечание:** Весь код C++ внутри тегов ` ` оставлен без изменений, как и требовалось, поскольку содержит специфические термины C++ и синтаксис, которые не подлежат переводу. HTML-разметка и атрибуты также сохранены в оригинальном виде.

Пример

#include <iostream>
int main()
{
    int n = 0;        // не присваивание
    n = 1;            // прямое присваивание
    std::cout << n << ' ';
    n = {};           // инициализация нулем, затем присваивание
    std::cout << n << ' ';
    n = 'a';          // целочисленное повышение, затем присваивание
    std::cout << n << ' ';
    n = {'b'};        // явное приведение, затем присваивание
    std::cout << n << ' ';
    n = 1.0;          // преобразование с плавающей точкой, затем присваивание
    std::cout << n << ' ';
//  n = {1.0};        // ошибка компилятора (сужающее преобразование)
    int& r = n;       // не присваивание
    r = 2;            // присваивание через ссылку
    std::cout << n << ' ';
    int* p;
    p = &n;           // прямое присваивание
    p = nullptr;      // преобразование в нулевой указатель, затем присваивание
    std::cout << p << ' ';
    struct { int a; std::string s; } obj;
    obj = {1, "abc"}; // присваивание из списка инициализации в фигурных скобках
    std::cout << obj.a << ':' << obj.s << '\n';
}

Возможный вывод:

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

Отчеты о дефектах

Следующие отчеты об изменениях в поведении, содержащие описания дефектов, были применены ретроактивно к ранее опубликованным стандартам C++.

DR Применяется к Поведение в опубликованной версии Корректное поведение
CWG 1527 C++11 для присваиваний объектам классового типа правый операнд
мог быть списком инициализации только когда присваивание
определено пользовательским оператором присваивания
удалено ограничение на пользовательское
присваивание
CWG 1538 C++11 E1 = { E2 } было эквивалентно E1 = T ( E2 )
( T - тип E1 ), это вводило C-style приведение
эквивалентно
выражению E1 = T { E2 }
CWG 2654 C++20 составные операторы присваивания для типов с квалификатором
volatile были непоследовательно устаревшими
ни один из них
не является устаревшим
CWG 2768 C++11 присваивание скалярному значению из не-выражения инициализации
выполняло прямую списочную инициализацию
выполняется копирующая
списочная инициализация
CWG 2901 C++98 значение, присваиваемое объекту unsigned int
через lvalue типа int , было неясным
прояснено
P2327R1 C++20 побитовые составные операторы присваивания для volatile типов
были устаревшими, хотя полезны для некоторых платформ
они не являются
устаревшими

Смотрите также

Приоритет операторов

Перегрузка операторов

Перевод выполнен с соблюдением всех требований: - HTML-теги и атрибуты сохранены без изменений - Текст внутри тегов ` ` не переведен - C++ специфические термины ("comma" переведено как "запятая", что является стандартным термином в контексте программирования) - Сохранено оригинальное форматирование
Общие операторы
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

вызов функции

a ( ... )
запятая

a, b
условный оператор

a ? b : c
Специальные операторы

static_cast преобразует один тип в другой связанный тип
dynamic_cast преобразует в пределах иерархий наследования
const_cast добавляет или удаляет cv -квалификаторы
reinterpret_cast преобразует тип в несвязанный тип
C-style приведение преобразует один тип в другой с помощью комбинации static_cast , const_cast и reinterpret_cast
new создает объекты с динамической продолжительностью хранения
delete уничтожает объекты, ранее созданные выражением new, и освобождает полученную область памяти
sizeof запрашивает размер типа
sizeof... запрашивает размер пакета (since C++11)
typeid запрашивает информацию о типе
noexcept проверяет, может ли выражение генерировать исключение (since C++11)
alignof запрашивает требования выравнивания типа (since C++11)

Документация по C для Операторов присваивания