初始化列表中的多个突变是否未定义行为? [英] Are multiple mutations within initializer lists undefined behavior?

查看:180
本文介绍了初始化列表中的多个突变是否未定义行为?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很好奇初始化列表和序列点。我刚才读到,初始化列表中的求值顺序是从左到右。如果是这样,那么在评价点之间必须有某种顺序点,我错了吗?那么说的是以下有效的代码?是否有任何引起未定义行为的内容?

I am curious about initializer lists and sequence points. I read a while ago that the order of evaluation in initializer lists is left to right. If that is so, then there must be some kind of sequence point between the points of evaluation, am I wrong? So with that said is the following valid code? Is there anything that causes undefined behavior in it?

int i = 0;

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

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

任何及所有回应表示赞赏。

Any and all responses are appreciated.

推荐答案

是的,代码是有效的,没有未定义的行为。 initizalizer列表中的表达式在对 S 的构造函数求值之前从左到右进行评估和排序。因此,您的程序应该始终为变量 i 赋值 2

Yes, the code is valid and does not have undefined behavior. Expressions in an initizalizer list are evaluated left-to-right and sequenced before the evaluation of the constructor of S. Therefore, your program should consistently assign value 2 to variable i.

引用C ++标准的第8.5.4节:

Quoting § 8.5.4 of the C++ Standard:

在braced-init-list的初始化器列表中,initializer-子句,包括从包展开(14.5.3)的任何结果,按出现的顺序 进行评估。也就是说,每个值计算和副作用给定初始化子句之前排序每个值计算和副作用之前,与初始化器列表的逗号分隔列表中的任何initializer子句相关联。

"Within the initializer-list of a braced-init-list, the initializer-clauses, including any that result from pack expansions (14.5.3), are evaluated in the order in which they appear. That is, every value computation and side effect associated with a given initializer-clause is sequenced before every value computation and side effect associated with any initializer-clause that follows it in the comma-separated list of the initializer-list."

因此,会发生什么:


  1. 的第一个参数的构造函数);

  2. ++ i c> S 的第二个参数的构造函数);

  3. S 的执行;

  4. 执行转换操作符,返回值 2 ;
  5. $ 分配给 i 已经有价值 2 )。

  1. ++i gets evaluated, yielding i = 1 (first argument of S's constructor);
  2. ++i gets evaluated, yielding i = 2 (second argument of S's constructor);
  3. S's constructor is executed;
  4. S's conversion operator is executed, returning value 2;
  5. value 2 is assigned to i (which already had value 2).

1.9 / 15,其中还提到类似的例子,有未定义的行为:

Another relevant paragraph of the Standard is § 1.9/15, which also mentions similar examples that do have undefined behavior:

i = v[i++]; // the behavior is undefined
i = i++ + 1; // the behavior is undefined

但是,同一段说:

除非另有说明,否则对个别运算符的操作数和各个表达式的子表达式的求值是无序的[...] / strong>(无论函数是否为内联函数),与任何参数表达式或与指定被调用函数的后缀表达式相关联的每个值计算和副作用在执行调用的主体中的每个表达式或语句之前函数。

"Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] When calling a function (whether or not the function is inline), every value computation and side effect associated with any argument expression, or with the postfix expression designating the called function, is sequenced before execution of every expression or statement in the body of the called function."

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

Since 1) the evaluation of the expressions in the initializer list is sequenced left-to-right, 2) the execution of the constructor of S is sequenced after the evaluation of all expressions in the initializer list, and 3) the assignment to i is sequenced after the execution of the constructor of S (and its conversion operator), the behavior is well-defined.

这篇关于初始化列表中的多个突变是否未定义行为?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆