Increment/decrement operators
递增/递减运算符对对象的值进行递增或递减操作。
| 运算符名称 | 语法 | 可重载 | 原型示例(针对 class T ) | |
|---|---|---|---|---|
| 类内定义 | 类外定义 | |||
| 前置递增 |
++a
|
是 | T & T :: operator ++ ( ) ; | T & operator ++ ( T & a ) ; |
| 前置递减 |
--a
|
是 | T & T :: operator -- ( ) ; | T & operator -- ( T & a ) ; |
| 后置递增 |
a++
|
是 | T T :: operator ++ ( int ) ; | T operator ++ ( T & a, int ) ; |
| 后置递减 |
a--
|
是 | T T :: operator -- ( int ) ; | T operator -- ( T & a, int ) ; |
|
||||
目录 |
前缀运算符
前缀递增和递减表达式的形式为
++
表达式
|
|||||||||
--
表达式
|
|||||||||
内建前缀运算符
|
(C++17 前) |
|
(C++17 起) |
|
(C++20 起) |
- 若 表达式 的类型为(可能带有 cv 限定符的) bool ,则程序非良构。
|
(since C++20) |
重载
在
针对用户定义运算符的重载决议
中,对于每个可选地带有 volatile 限定的算术类型
A
(不包括
bool
),以及对于每个指向可选地带有 cv 限定对象类型的可选地带有 volatile 限定指针
P
,以下函数签名会参与重载决议:
|
A
&
operator
++
(
A
&
)
|
||
|
bool
&
operator
++
(
bool
&
)
|
(已弃用) (直至 C++17) | |
|
P
&
operator
++
(
P
&
)
|
||
|
A
&
operator
--
(
A
&
)
|
||
|
P
&
operator
--
(
P
&
)
|
||
后缀运算符
后缀递增和递减表达式的形式为
表达式
++
|
|||||||||
表达式
--
|
|||||||||
内置后缀运算符
后缀递增或递减的结果是通过对 表达式 (在修改前)应用 左值到右值转换 所获得的值。结果的类型是 表达式 类型的cv非限定版本。
如果 expression 不是算术类型( 不包含(可能 cv 限定的) bool (C++17 起) 的可修改左值,或不是指向完整对象类型的指针,则程序非良构。
|
如果 expression 的类型带有 volatile 限定符,则不推荐使用递增或递减操作。 |
(since C++20) |
++
运算符的操作数。
--
运算符的操作数。
后缀递增或递减的值计算在修改 表达式 之前 定序完成 。相对于不确定顺序的函数调用,后缀递增或递减的操作属于单次求值。
重载
在
针对用户定义运算符的重载决议
中,对于每个可选地带有 volatile 限定的算术类型
A
(不包括
bool
),以及对于每个指向可选地带有 cv 限定对象类型的可选地带有 volatile 限定指针
P
,以下函数签名会参与重载决议:
|
A operator
++
(
A
&
,
int
)
|
||
|
bool
operator
++
(
bool
&
,
int
)
|
(已弃用) (直至 C++17) | |
|
P operator
++
(
P
&
,
int
)
|
||
|
A operator
--
(
A
&
,
int
)
|
||
|
P operator
--
(
P
&
,
int
)
|
||
示例
#include <iostream> int main() { int n1 = 1; int n2 = ++n1; int n3 = ++ ++n1; int n4 = n1++; // int n5 = n1++ ++; // 错误 // int n6 = n1 + ++n1; // 未定义行为 std::cout << "n1 = " << n1 << '\n' << "n2 = " << n2 << '\n' << "n3 = " << n3 << '\n' << "n4 = " << n4 << '\n'; }
输出:
n1 = 5 n2 = 2 n3 = 4 n4 = 4
注释
由于涉及副作用,必须谨慎使用内置递增和递减运算符,以避免因违反 顺序规则 而导致未定义行为。
由于在后置递增和后置递减过程中会构造对象的临时副本,在不需要使用返回值的场景中,前置递增或前置递减运算符通常具有更高效率。
标准库
递增和递减运算符为许多标准库类型进行了重载。特别地,每个 LegacyIterator 都重载了 operator ++ ,而每个 LegacyBidirectionalIterator 都重载了 operator -- ,即使这些运算符对于特定迭代器可能是空操作。
算术类型的重载 |
|
|
将原子值递增或递减一
(
std::atomic<T>
的公开成员函数)
|
|
|
递增或递减滴答计数
(
std::chrono::duration<Rep,Period>
的公开成员函数)
|
|
迭代器类型的重载 |
|
|
推进迭代器
(
std::raw_storage_iterator<OutputIt,T>
的公开成员函数)
|
|
推进或递减
reverse_iterator
(
std::reverse_iterator<Iter>
的公开成员函数)
|
|
推进或递减
move_iterator
(
std::move_iterator<Iter>
的公开成员函数)
|
|
|
无操作
(
std::front_insert_iterator<Container>
的公开成员函数)
|
|
|
无操作
(
std::back_insert_iterator<Container>
的公开成员函数)
|
|
|
无操作
(
std::insert_iterator<Container>
的公开成员函数)
|
|
|
推进迭代器
(
std::istream_iterator<T,CharT,Traits,Distance>
的公开成员函数)
|
|
|
无操作
(
std::ostream_iterator<T,CharT,Traits>
的公开成员函数)
|
|
|
推进迭代器
(
std::istreambuf_iterator<CharT,Traits>
的公开成员函数)
|
|
|
无操作
(
std::ostreambuf_iterator<CharT,Traits>
的公开成员函数)
|
|
|
将迭代器推进到下一个匹配
(
std::regex_iterator<BidirIt,CharT,Traits>
的公开成员函数)
|
|
|
将迭代器推进到下一个子匹配
(
std::regex_token_iterator<BidirIt,CharT,Traits>
的公开成员函数)
|
|
缺陷报告
以下行为变更缺陷报告被追溯应用于先前发布的C++标准。
| 缺陷报告 | 适用标准 | 发布时行为 | 正确行为 |
|---|---|---|---|
| CWG 2855 | C++98 |
对内置前缀递增和前缀递减运算符应用了常规算术转换,
但未对其后缀版本应用 [1] |
同时应用 |
| CWG 2901 | C++98 |
对内置后缀递增和后缀递减运算符
未应用左值到右值转换 |
已应用 |
- ↑ 前缀形式 ++ x 等价于 x + = 1 ,而后者适用于常规算术转换(即生成 decltype ( x ) 与 int 之间的公共类型)。然而,后缀形式 x ++ 的效果仅为“将 x 的值加一”,此时不存在二元运算符,因此不会发生常规算术转换。
参见
| 常用运算符 | ||||||
|---|---|---|---|---|---|---|
| 赋值 |
自增
自减 |
算术 | 逻辑 | 比较 |
成员
访问 |
其他 |
|
a
=
b
|
++
a
|
+
a
|
!
a
|
a
==
b
|
a
[
...
]
|
函数调用
a ( ... ) |
|
逗号
a, b |
||||||
|
条件
a ? b : c |
||||||
| 特殊运算符 | ||||||
|
static_cast
将一种类型转换为另一种相关类型
|
||||||
|
C 文档
关于
自增/自减运算符
|