赋值运算符

C++

编译器支持

自由(freestanding)与宿主(hosted)

语言

标准库

标准库头文件

具名要求

特性测试宏 (C++20)

语言支持库

概念库 (C++20)

诊断库

内存管理库

元编程库 (C++11)

通用工具库

容器库

迭代器库

范围库 (C++20)

算法库

字符串库

文本处理库

数值库

日期和时间库

输入/输出库

文件系统库 (C++17)

并发支持库 (C++11)

执行控制库 (C++26)

技术规范

符号索引

外部库

[编辑] C++ 语言

通用主题

预处理器

注释

关键词

转义序列

流程控制

条件执行语句

if

switch

迭代语句(循环)

for

范围-for (C++11)

while

do-while

跳转语句

continue - break

goto - return

函数

函数声明

Lambda 函数表达式

inline 说明符

动态异常规范 (直到 C++17*)

noexcept 说明符 (C++11)

异常

throw 表达式

try 块

catch 处理程序

命名空间

命名空间声明

命名空间别名

类型

基本类型

枚举类型

函数类型

类/结构体类型

联合类型

说明符

const/volatile

decltype (C++11)

auto (C++11)

constexpr (C++11)

consteval (C++20)

constinit (C++20)

存储期说明符

初始化

默认初始化

值初始化

零初始化

复制初始化

直接初始化

聚合初始化

列表初始化 (C++11)

常量初始化

引用初始化

表达式

值类别

求值顺序

运算符

运算符优先级

替代表示

字面量

布尔 - 整型 - 浮点型

字符 - 字符串 - nullptr (C++11)

用户定义 (C++11)

工具

属性 (C++11)

类型

typedef 声明

类型别名声明 (C++11)

类型转换

隐式转换

static_cast

const_cast

显式转换

dynamic_cast

reinterpret_cast

内存分配

new 表达式

delete 表达式

类

类声明

构造函数

this 指针

访问说明符

friend 说明符

类特有的函数属性

虚函数

override 说明符 (C++11)

final 说明符 (C++11)

explicit (C++11)

static

特殊成员函数

默认构造函数

复制构造函数

移动构造函数 (C++11)

复制赋值

移动赋值 (C++11)

析构函数

模板

类模板

函数模板

模板特化

参数包 (C++11)

杂项

内联汇编

C++ 历史

[编辑] 表达式

通用

值类别

求值顺序

常量表达式

主表达式

Lambda 表达式 (C++11)

Requires 表达式 (C++20)

包索引表达式 (C++26)

潜在求值表达式

字面量

整数字面量

浮点数字面量

布尔字面量

字符字面量

转义序列

字符串字面量

空指针字面量 (C++11)

用户定义字面量 (C++11)

运算符

赋值运算符

递增和递减

算术运算符

逻辑运算符

比较运算符

成员访问运算符

其他运算符

new 表达式

delete 表达式

throw 表达式

alignof

sizeof

sizeof... (C++11)

typeid

noexcept (C++11)

折叠表达式 (C++17)

运算符的替代表示

优先级和结合性

运算符重载

默认比较 (C++20)

转换

隐式转换

显式转换

常用算术转换

用户定义转换

const_cast

static_cast

dynamic_cast

reinterpret_cast

[编辑]

赋值运算符修改对象的值。

运算符名称

语法

可重载

原型示例(对于 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 在内的任何类型。

目录

1 定义

2 赋值运算符语法

3 内置简单赋值运算符

3.1 从表达式赋值

3.2 从非表达式初始化子句赋值

4 内置复合赋值运算符

5 示例

6 缺陷报告

7 参阅

[编辑] 定义

复制赋值将对象 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 不能是逗号表达式,因为它的优先级较低。

1) 简单赋值表达式。

2) 复合赋值表达式。

如果 new-value 不是表达式,则赋值表达式永远不会匹配重载的复合赋值运算符。

(C++11 起)

[编辑] 内置简单赋值运算符

对于内置简单赋值,target-expr 必须是可修改的左值。

由 target-expr 引用的对象通过将其值替换为 new-value 的结果而被修改。如果引用的对象是整型 T,并且 new-value 的结果是对应的有符号/无符号整型,则对象的值将替换为类型 T 的值,其值表示与 new-value 的结果相同。

内置简单赋值的结果是 target-expr 类型的左值,引用 target-expr。如果 target-expr 是位域,则结果也是位域。

[编辑] 从表达式赋值

如果 new-value 是表达式,它会隐式转换为 target-expr 的 cv-无限定类型。当 target-expr 是不能表示表达式值的位域时,位域的最终值是实现定义的。

如果 target-expr 和 new-value 标识重叠对象,则行为未定义(除非重叠完全且类型相同)。

如果 target-expr 的类型是 volatile 限定的,则赋值被弃用,除非(可能带括号的)赋值表达式是丢弃值表达式或未求值操作数。

(C++20 起)

从非表达式初始化子句赋值

new-value 仅在以下情况才允许不是表达式:

target-expr 是标量类型 T,并且 new-value 为空或只有一个元素。在这种情况下,给定一个发明的变量 t 声明并初始化为 T t = new-value ,x = new-value  的含义是 x = t。 target-expr 是类类型。在这种情况下,new-value 作为通过重载决议选择的赋值运算符函数的参数传递。

#include

std::complex 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

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';

}

可能的输出

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

[编辑] 缺陷报告

下列更改行为的缺陷报告追溯地应用于以前出版的 C++ 标准。

缺陷报告

应用于

发布时的行为

正确的行为

CWG 1527

C++11

对于类类型对象的赋值,右操作数只能是初始化列表,当赋值由用户定义的赋值运算符定义时

移除用户定义赋值约束

CWG 1538

C++11

E1 = {E2} 等价于 E1 = T(E2)(T 是 E1 的类型),这引入了 C 风格的转换

它等价于E1 = T{E2}

CWG 2654

C++20

volatile 限定类型的复合赋值运算符被不一致地弃用

它们都没有被弃用

CWG 2768

C++11

从非表达式初始化子句赋值到标量值会执行直接列表初始化

改为执行复制列表初始化

CWG 2901

C++98

通过 int 左值赋值给 unsigned int对象的值不明确

已明确

P2327R1

C++20

volatile 类型的按位复合赋值运算符在某些平台上很有用,但被弃用

它们没有被弃用

[编辑] 另请参阅

运算符优先级

运算符重载

常见运算符

赋值

递增递减

算术

逻辑

比较

成员访问

其他

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

++a

--aa++a--

+a

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

!aa && ba || b

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

a[...]

*a

&aa->ba.ba->*ba.*b

函数调用a(...)

逗号a, b

条件a ? b : c

特殊运算符

static_cast 将一种类型转换为另一种相关类型

dynamic_cast 在继承层次结构内进行转换

const_cast 添加或移除 cv-限定符

reinterpret_cast 将类型转换为不相关类型

C 风格转换通过 static_cast、const_cast 和 reinterpret_cast 的混合将一种类型转换为另一种类型

new 创建具有动态存储期的对象

delete 销毁先前由 new 表达式创建的对象并释放获得的内存区域

sizeof 查询类型的大小

sizeof... 查询 包 的大小 (C++11 起)

typeid 查询类型的类型信息

noexcept 检查表达式是否可以抛出异常 (C++11 起)

alignof 查询类型的对齐要求 (C++11 起)

C 文档,关于 赋值运算符