在C++里,表达式求值顺序一直是一个大坑,这是由于为了给编译器更大的优化空间,C++对表达式的求值做了许多非常灵活的规定(其实就是不规定,编译器愿意怎么实现都可以)。这些灵活的规定也给C++带来了许多在其它语言中不存在的未定义行为(undefined behavior),比如i=i++,甚至有一些是标准委员会都没有预想到。
在C++03里,表达式的求值顺序依靠序列点(sequency point)来定义。有关序列点的介绍,在 这里 和 这里 可以见到。但是其中也提到了序列点所存在的一些问题。到了C++11,标准委员会放弃了序列点,而使用了一种新的方式定义表达的求值顺序。两种定义的结果大同小异,这里使用C++11的定义方式,介绍一下C++中的表达式求值。
C++11中还引入线程的概念,不过这里讨论的是同一线程中表达式的求值顺序,不讨论不同线程之间的顺序与同步的问题。
一些定义
side effect 副作用
访问(读或写)volatile的变量,修改一个对象(变量),调用系统I/O函数,或调用会发生以上三种行为函数,统称为副作用。对表达式的求值,不只包括求出表达式值(即返回值,value computation),还包括完成表达式中的包含的各种副作为。
如
int i=1;
i++; // 对其求值包括两部分,计算返回值(1),以及其副作用(将i赋值为2)
full-expression 完整表达式
一个完整式指不是其它表达式子表达式的表达式。
一个表达式可以包含子表达式,也可以成为其它表达式的一部分,如(y=i+1)!=0; 中,y=i+1 包含子表达式 i+1 ,同时它是整个表达式(y=i+1)!=0的一个子表达式。在这里(y=i+1)!=0就是一个完整表达式。
一个完整表达式包括根据表达式所在上下文成生成类