Assignment operators
Операторы присваивания изменяют значение объекта.
| Название оператора | Синтаксис | Перегружаемый | Примеры прототипов (для 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 ) ; |
|
||||
Содержание |
Определения
Копирующее присваивание заменяет содержимое объекта 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) для присваивания цели |
- ↑ target-expr должен иметь более высокий приоритет чем выражение присваивания.
- ↑ new-value не может быть выражением с запятой, поскольку его приоритет ниже.
|
Если 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 разрешается не быть выражением только в следующих случаях:
#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
)
;
|
||
Для каждой пары
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
)
;
|
||
Для каждого опционально 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
)
;
|
||
Пример
#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 типов
были устаревшими, хотя полезны для некоторых платформ |
они не являются
устаревшими |
Смотрите также
| Общие операторы | ||||||
|---|---|---|---|---|---|---|
| assignment |
increment
decrement |
arithmetic | logical | comparison |
member
access |
other |
|
a
=
b
|
++
a
|
+
a
|
!
a
|
a
==
b
|
a
[
...
]
|
вызов функции
a ( ... ) |
|
запятая
a, b |
||||||
|
условный оператор
a ? b : c |
||||||
| Специальные операторы | ||||||
|
static_cast
преобразует один тип в другой связанный тип
|
||||||
|
Документация по C
для
Операторов присваивания
|