命名空间
变体
操作

自增/自减运算符

出自 cppreference.cn
< cpp‎ | language
 
 
C++ 语言
通用主题
流程控制
条件执行语句
if
迭代语句 (循环)
for
范围 for (C++11)
跳转语句
函数
函数声明
Lambda 函数表达式
inline 说明符
动态异常规范 (于 C++17* 中弃用)
noexcept 说明符 (C++11)
异常
命名空间
类型
说明符
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
存储期说明符
初始化
 
 

自增/自减运算符递增或递减对象的值。

运算符名称 语法 可重载 原型示例 (对于 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,但有以下例外
  • 如果 表达式 的类型为(可能带 volatile 限定的)bool,则 表达式 会被设为 true。这种自增已被弃用。
(直至 C++17)
  • 如果 表达式 的类型为(可能带 cv 限定的)bool,则程序为非良构。
(自 C++17 起)
  • 如果 表达式 的类型是 volatile 限定的,则自增已被弃用。
(自 C++20 起)
2) 表达式 --x 等价于 x -= 1,但有以下例外
  • 如果 表达式 的类型为(可能带 cv 限定的)bool,则程序为非良构。
  • 如果 表达式 的类型是 volatile 限定的,则自减已被弃用。
(自 C++20 起)

[编辑] 重载

针对用户定义运算符的重载决议中,对于每个可选地带有 volatile 限定的算术类型 A (除了 bool)以及对于每个可选地带有 volatile 限定的指针 P ,指向可选地带有 cv 限定的对象类型,以下函数签名参与重载决议

A& operator++(A&)
bool& operator++(bool&)
(已弃用)(直至 C++17)
P& operator++(P&)
A& operator--(A&)
P& operator--(P&)

[编辑] 后缀运算符

后缀自增和自减表达式具有以下形式

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

[编辑] 内置后缀运算符

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

如果 表达式 不是算术类型的可修改左值 (除了(可能带 cv 限定的) bool之外)(自 C++17 起),或者指向完整对象类型的指针,则程序为非良构。

如果 表达式 的类型是 volatile 限定的,则自增或自减已被弃用。

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

后缀自增或自减的值计算先于 表达式 的修改进行。关于不确定顺序的函数调用,后缀自增或自减的操作是单次求值。

[编辑] 重载

针对用户定义运算符的重载决议中,对于每个可选地带有 volatile 限定的算术类型 A (除了 bool)以及对于每个可选地带有 volatile 限定的指针 P ,指向可选地带有 cv 限定的对象类型,以下函数签名参与重载决议

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++ ++;   // error
//  int n6 = n1 + ++n1; // undefined behavior
    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++ 标准。

DR 应用于 已发布行为 正确行为
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_castconst_castreinterpret_cast 将一种类型转换为另一种类型
new 创建具有动态存储期的对象
delete 析构先前由 new 表达式创建的对象并释放获得的内存区域
sizeof 查询类型的大小
sizeof... 查询形参包的大小 (自 C++11 起)
typeid 查询类型的类型信息
noexcept 检查表达式是否可以抛出异常 (自 C++11 起)
alignof 查询类型的对齐要求 (自 C++11 起)

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