首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >初始化器列表中的多个突变是否有未定义的行为?

初始化器列表中的多个突变是否有未定义的行为?
EN

Stack Overflow用户
提问于 2013-01-22 00:22:49
回答 2查看 772关注 0票数 21

我对初始化器列表和序列点很感兴趣。不久前我读到初始化器列表中的求值顺序是从左到右。如果是这样,那么在评估点之间一定有某种序列点,我错了吗?那么,下面的代码是有效的吗?其中是否存在导致未定义行为的原因?

代码语言:javascript
复制
int i = 0;

struct S {
    S(...) {} 
    operator int() { return i; }
};

int main() {
    i = S{++i, ++i};
}

任何和所有的回应都是值得感谢的。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-01-22 00:30:01

是的,代码是有效的,没有未定义的行为。在计算S的构造函数之前,初始化器列表中的表达式从左到右进行计算和排序。因此,您的程序应该始终如一地为变量i赋值2

引用C++标准的§8.5.4:

在带括号的初始化列表的初始化器列表中,初始化器子句(包括任何由包扩展(14.5.3)产生的子句)将按照它们出现的顺序进行评估。也就是说,与给定的初始化器子句关联的每个值计算和副作用将在初始化程序列表的逗号分隔列表中与其后面的任何初始化器子句关联的每个值计算和副作用之前排序。

因此,发生的情况是:

  1. ++i求值,产生constructor);
  2. ++i (计算Si = 1的第一个参数,执行S的constructor);
  3. S's构造函数的第二个参数是2;
  4. value转换运算符,返回值2被赋值给i (它已经具有值2).

本标准的另一个相关段落是§1.9/15,其中也提到了具有未定义行为的类似示例:

代码语言:javascript
复制
i = v[i++]; // the behavior is undefined
i = i++ + 1; // the behavior is undefined

然而,同一段话说:

除非另有说明,否则对单个运算符的操作数和子表达式的计算是不排序的。...当调用函数(无论函数是否为内联函数)时,在执行被调用函数体中的每个表达式或语句之前,与任何参数表达式或指定被调用函数的后缀表达式相关联的每个值计算和副作用都会被排序。

由于1)初始化器列表中表达式的求值是从左到右排序的,2) S的构造函数的执行是在初始化器列表中的所有表达式求值之后排序的,3)对i的赋值是在S的构造函数(及其转换运算符)执行之后排序的,所以行为是定义良好的。

票数 19
EN

Stack Overflow用户

发布于 2013-01-22 20:49:07

是的,确实存在未定义行为的情况。

以下是导致未定义行为的情况的示例:

在一个序列点内,

  • A变量被多次更改。作为一个典型的例子,经常引用i=i++表达式,其中i变量的赋值和它的递增是同时执行的。要了解有关此类错误的更多信息,请在初始化变量之前阅读"sequence points".
  • Using a variable一节。尝试使用new []运算符使用variable.
  • Memory分配并使用delete运算符进行后续释放时,会发生未定义的行为。例如:t *p =新建T10;删除p;。正确的代码是:t *p =新建;T10 [] p;。

编辑的

此外,您的代码S{++i,++i};未针对VS2012进行编译。你的意思可能是S(++i,++i);?如果使用"()“,则存在未定义的行为。在其他情况下,源代码是不正确的。

票数 -2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14442894

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档