C++单语句内赋值取值与后置自增执行顺序异常问题
问题根因
这个现象的核心原因是你对C++语句的求值顺序、后置自增运算符的生效时机存在误解,写出了存在执行顺序歧义的代码。
关键规则说明
- 后置自增运算符
r++的逻辑是:返回r自增前的旧值,同时产生「将r的值+1」的副作用,这个副作用的生效时机在同一条完整语句内,和其他操作数的求值先后,在C++17标准前没有强制约束,由编译器自行决定。 - 你写的问题语句是
pos[cards[r]] = r++;,你预期的执行顺序是:- 计算左侧哈希表键:取当前r值,拿到
cards[r]作为key - 计算右侧赋值:取当前r的旧值,然后r自增
- 把右侧的旧值赋值给左侧哈希表对应key的位置
- 计算左侧哈希表键:取当前r值,拿到
但你使用的编译器实际选择的执行顺序是:
- 先处理右侧的
r++:拿到r的旧值,立刻触发r自增的副作用把r加1 - 再计算左侧的哈希表key:这时候r已经是自增后的值了,取到的是
cards[r+1]而不是预期的cards[r] - 把最开始拿到的r旧值,赋值给这个错误key对应的哈希表位置
以你测试用例第一次循环为例,初始r=0:
- 处理右侧r++,拿到旧值0,r变成1
- 计算左侧取cards[1] = 2,而不是预期的cards[0] = 1
- 给pos[2]赋值0,这就对应了你实际运行得到的第一个键值对
[2,0],后续循环全部偏移一位,最终得到错误的哈希表结果。
为什么拆分两行就正常
当你把逻辑拆成两个独立语句:
pos[cards[r]] = r; r++;
C++标准明确规定,前一条完整语句的所有执行逻辑和副作用全部完成后,才会开始执行下一条语句。执行顺序完全符合预期:
- 第一行执行时r还没自增,正确取到
cards[r]作为key,存入当前r值 - 第一行全部执行完毕,才会执行第二行把r加1,不存在顺序歧义。
补充提示:哪怕是C++17及之后的标准明确了赋值运算符先算右操作数、再算左操作数、最后赋值的顺序,你原来的单行写法依旧是错误的——右操作数求值时触发的r自增副作用,会在左操作数求值前就生效,依旧会取到错误的cards索引,这类把索引访问和同索引自增写在同一条赋值语句里的写法本身就应该主动规避。
内容的提问来源于stack exchange,提问作者Ankit
相关产品推荐
相关产品推荐

