为何用对象指针批量打印数组会出现结果倒序?
为什么批量打印对象数组时输出倒序?
这其实是C/C++里未定义行为导致的典型问题,核心原因是函数参数/表达式子项的求值顺序没有强制标准,咱们一步步理清楚:
先看你批量打印的那行代码:
cout << ((p++)->GetTires()) << " " << ((p++)->GetTires()) << " " << ((p++)->GetTires()) << " " << ((p++)->GetTires()) << endl;
你在这里把4个带副作用的操作(p++)塞进了同一个表达式里——而C/C++标准从来没规定过这类场景下子表达式的求值顺序,不同编译器(甚至同一编译器不同优化等级)可能选择从左到右、从右到左,或者其他奇怪的顺序。
你的编译器刚好选择了从右往左求值这4个(p++)->GetTires(),而且每个求值的副作用(p自增)会立即生效,具体过程是这样的:
- 初始
p指向数组第一个元素array[0]; - 编译器先计算最右侧的
(p++)->GetTires():先读取当前p指向的array[0]的值(2),然后p自增指向array[1]; - 接着计算倒数第二个表达式:读取
array[1]的值(4),p自增指向array[2]; - 再计算倒数第三个:读取
array[2]的值(6),p自增指向array[3]; - 最后计算最左侧的表达式:读取
array[3]的值(8),p自增指向数组末尾; - 而
cout的<<是左结合的,会按从左到右的顺序输出这四个表达式的结果——也就是8、6、4、2,刚好是倒序。
而你拆分到多个cout语句的情况就完全不同了:
cout << ((p++)->GetTires()) << " "; cout << ((p++)->GetTires()) << " "; // ...
每个cout都是一个独立的完整表达式,C++标准规定每个完整表达式结束后,所有副作用(比如p++的自增)都会被处理完毕。所以每一行都会先读取当前p指向的元素值,再自增p,自然就能按顺序输出2、4、6、8。
总结一下要注意的点:
- 永远不要在同一个表达式中多次对同一个对象执行带副作用的操作(比如自增、自减、赋值),这属于标准明确规定的未定义行为,结果完全不可预测;
- 如果需要按顺序操作,一定要拆分到不同的语句,或者使用有明确序列点的语法(比如逗号运算符,但注意参数列表里的逗号是分隔符,不是逗号运算符)。
内容的提问来源于stack exchange,提问作者A.H.M. Annur
相关产品推荐
相关产品推荐

