我对初始化器列表和序列点很感兴趣。不久前我读到初始化器列表中的求值顺序是从左到右。如果是这样,那么在评估点之间一定有某种序列点,我错了吗?那么,下面的代码是有效的吗?其中是否存在导致未定义行为的原因?
int i = 0;
struct S {
S(...) {}
operator int() { return i; }
};
int main() {
i = S{++i, ++i};
}
任何和所有的回应都是值得感谢的。
发布于 2013-01-22 00:30:01
是的,代码是有效的,没有未定义的行为。在计算S
的构造函数之前,初始化器列表中的表达式从左到右进行计算和排序。因此,您的程序应该始终如一地为变量i
赋值2
。
引用C++标准的§8.5.4:
在带括号的初始化列表的初始化器列表中,初始化器子句(包括任何由包扩展(14.5.3)产生的子句)将按照它们出现的顺序进行评估。也就是说,与给定的初始化器子句关联的每个值计算和副作用将在初始化程序列表的逗号分隔列表中与其后面的任何初始化器子句关联的每个值计算和副作用之前排序。
因此,发生的情况是:
对
++i
求值,产生constructor);++i
(计算S
的i = 1
的第一个参数,执行S
的constructor);S
's构造函数的第二个参数是2
;2
被赋值给i
(它已经具有值2
).本标准的另一个相关段落是§1.9/15,其中也提到了具有未定义行为的类似示例:
i = v[i++]; // the behavior is undefined
i = i++ + 1; // the behavior is undefined
然而,同一段话说:
除非另有说明,否则对单个运算符的操作数和子表达式的计算是不排序的。...当调用函数(无论函数是否为内联函数)时,在执行被调用函数体中的每个表达式或语句之前,与任何参数表达式或指定被调用函数的后缀表达式相关联的每个值计算和副作用都会被排序。
由于1)初始化器列表中表达式的求值是从左到右排序的,2) S
的构造函数的执行是在初始化器列表中的所有表达式求值之后排序的,3)对i
的赋值是在S
的构造函数(及其转换运算符)执行之后排序的,所以行为是定义良好的。
发布于 2013-01-22 20:49:07
是的,确实存在未定义行为的情况。
以下是导致未定义行为的情况的示例:
在一个序列点内,
编辑的
此外,您的代码S{++i,++i};未针对VS2012进行编译。你的意思可能是S(++i,++i);?如果使用"()“,则存在未定义的行为。在其他情况下,源代码是不正确的。
https://stackoverflow.com/questions/14442894
复制相似问题