Namespaces
Variants

Increment/decrement 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 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 ) ;
备注
  • 内置运算符的前缀版本返回 引用 而后缀版本返回 ,典型的 用户定义重载 遵循此模式,使得用户定义运算符可以像内置运算符一样使用。但在用户定义的运算符重载中,可以使用任何类型作为返回类型(包括 void )。
  • int 参数是用于区分运算符前缀和后缀版本的哑元参数。当调用用户定义的后缀运算符时,传入该参数的值始终为零,但可以通过函数调用表示法调用运算符来更改此值(例如 a. operator ++ ( 2 ) operator ++ ( a, 2 ) )。

目录

前缀运算符

前缀递增和递减表达式的形式为

++ 表达式
-- 表达式
1) 前缀递增(预递增)
2) 前缀递减(预递减)

内建前缀运算符

1) 表达式 ++ x 等价于 x + = 1 ,但存在以下例外:
  • expression 的类型为(可能带有 volatile 限定符的) bool ,则 expression 被设置为 true 。此类自增操作已被弃用。
(C++17 前)
  • expression 的类型为(可能带有 cv 限定符的) bool ,则程序非良构。
(C++17 起)
  • expression 的类型带有 volatile 限定符,则自增操作被弃用。
(C++20 起)
2) 表达式 -- x 等价于 x - = 1 ,但存在以下例外情况:
  • 表达式 的类型为(可能带有 cv 限定符的) bool ,则程序非良构。
  • 表达式 的类型带有 volatile 限定符,则递减操作被弃用。
(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 & )

后缀运算符

后缀递增和递减表达式的形式为

表达式 ++
表达式 --
1) 后缀递增(后递增)
2) 后缀递减(后递减)

内置后缀运算符

后缀递增或递减的结果是通过对 表达式 (在修改前)应用 左值到右值转换 所获得的值。结果的类型是 表达式 类型的cv非限定版本。

如果 expression 不是算术类型( 不包含(可能 cv 限定的) bool (C++17 起) 的可修改左值,或不是指向完整对象类型的指针,则程序非良构。

如果 expression 的类型带有 volatile 限定符,则不推荐使用递增或递减操作。

(since C++20)
1) 表达式 的值被修改,如同它是前缀 ++ 运算符的操作数。
2) 表达式 的值被修改,如同它是前缀 -- 运算符的操作数。

后缀递增或递减的值计算在修改 表达式 之前 定序完成 。相对于不确定顺序的函数调用,后缀递增或递减的操作属于单次求值。

重载

针对用户定义运算符的重载决议 中,对于每个可选地带有 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 对内置后缀递增和后缀递减运算符
未应用左值到右值转换
已应用
  1. 前缀形式 ++ x 等价于 x + = 1 ,而后者适用于常规算术转换(即生成 decltype ( x ) int 之间的公共类型)。然而,后缀形式 x ++ 的效果仅为“将 x 的值加一”,此时不存在二元运算符,因此不会发生常规算术转换。

参见

运算符优先级

运算符重载

常用运算符
赋值 自增
自减
算术 逻辑 比较 成员
访问
其他

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风格转换 通过混合使用 static_cast const_cast reinterpret_cast 将一种类型转换为另一种类型
new 创建具有动态存储期的对象
delete 销毁先前由 new 表达式创建的对象并释放获取的内存区域
sizeof 查询类型的大小
sizeof... 查询 参数包 的大小 (自 C++11 起)
typeid 查询类型的类型信息
noexcept 检查表达式是否能抛出异常 (自 C++11 起)
alignof 查询类型的对齐要求 (自 C++11 起)

C 文档 关于 自增/自减运算符