i++ 通常比 ++i 慢,因其需先保存原值再自增并返回副本,而 ++i 直接修改并返回引用,无拷贝开销;未优化时差异明显,优化后汇编常一致。

为什么 i++ 通常比 ++i 慢(原生类型)
对内置整型(如 int、long)而言,编译器在优化充分时两者生成的汇编往往一致,但语义上 i++ 必须返回自增前的值,这意味着它隐含一个临时副本。即使被优化掉,在未开启优化(如 -O0)或调试模式下,i++ 仍会多一次值拷贝操作。
-
++i直接修改i并返回其引用(int&),无副本 -
i++需先保存原值,再自增,最后返回该保存值(通常是int值,非引用) - 对于简单类型,差异微小;但若写成循环惯用写法(如
for (int i = 0; i ),习惯用++i更符合语义且避免潜在冗余
std::vector::iterator 等自定义迭代器中重载 ++i 和 i++ 的典型写法
用户自定义类型(如迭代器、智能指针)重载自增运算符时,效率差异变得显著——因为拷贝构造开销不可忽略。标准做法是让前置版本返回引用,后置版本返回值对象,并借助 int 形参区分重载。
- 前置
++i:声明为T& operator++(),直接修改对象并返回*this - 后置
i++:声明为T operator++(int),先保存当前状态副本,再调用前置版本,最后返回副本 - 常见错误:后置版本误返回
*this引用(导致返回已修改对象),或未用int形参导致重载失败
T& operator++() {
++ptr_; // 实际移动逻辑
return *this;
}
T operator++(int) {
T tmp(*this); // 关键:复制当前状态
++(*this); // 复用前置逻辑
return tmp; // 返回旧值
}
什么时候 i++ 和 ++i 行为完全等价?
仅当表达式结果被彻底丢弃(即不参与后续计算、不赋值、不传参)时,两者效果相同,编译器也更可能将它们优化为同一指令序列。
- 例如:
for (int i = 0; i 与for (int i = 0; i 在-O2下几乎无差别 - 但
auto x = i++;和auto x = ++i;绝对不等价,前者x是旧值,后者是新值 - 在模板或泛型代码中(如
std::sort内部调用迭代器自增),应无条件使用++it,因为无法预设迭代器是否廉价可拷贝
重载时容易忽略的 const 正确性与返回类型陷阱
前置 ++i 若用于 const 对象,必须拒绝编译;而后置 i++ 即使作用于 const 对象,也可能意外通过——如果返回类型不是 const T 或实现有误。
立即学习“C++免费学习笔记(深入)”;
- 前置版本不应接受
const T&为this,否则允许修改常量对象;正确做法是不提供const成员函数版本 - 后置版本返回的是值,天然脱离原对象 const 性质,但若返回
T&就构成严重错误(返回局部对象引用) - 若类支持 move 语义,后置版本可考虑返回
T&&(极少必要),但标准实践仍是返回T值









