在C ++ 11,如何确定什么是“排序前”的其他人? [英] In C++11, how to determine what is 'sequenced before' others?

查看:112
本文介绍了在C ++ 11,如何确定什么是“排序前”的其他人?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我参与了有关未定义行为和序列[之前/之后]的 这个出色的答案 ,关系在C ++ 11。



对于这些熟悉的示例,顺序是如何实现的?规则适用?


  1. i = ++ i;

  2. a [++ i] = i;

更具体来说,新的C ++ 11排序规则是什么?



我正在寻找一些规则)


'='

lhs / code>语句总是在 rhs 之前排序,因此首先计算。



b $ b

如果这些在标准本身可用,有人可以在这里报价相同吗?感谢。

解决方案

之前的顺序关系,关于它的规则是整理与先前的规则关于序列点的定义,以与其他存储器模型关系一致的方式定义,诸如发生在之前同步以便可以精确地指定



对于简单的单线程代码,规则的后果不会改变。



让我们从你的例子开始:



1。 i = ++ i;



如果 i 一个内置的类型如 int 那么没有涉及的函数调用,一切都是内置的运算符。因此,有4种情况发生:



(a) ++ i 值计算 $ c>,即 +1



(b) ++ i 副作用,其存储原始值的 +1 返回 i



++ i 值计算结果的值,



(d)作业的副作用,将新值储存到 i



所有这些都是顺序之前的完整表达式。 (即它们都由语句的最后一个分号完成)



由于 ++ i code> i + = 1 ,存储值的副作用顺序 > (a)之前

$ <$ p
<

赋值的两个操作数的值计算在赋值本身的值计算之前进行排序,依次存储值的次序之前。因此,(a)在(c)之前进行测序,和(c)在(d)之前进行测序。



我们因此有(b) - >(a) - >(c) - >(d),因此这在新规则下是正常的,而在C ++ 98下不行。



如果 i ,那么表达式将是 i.operator =(i.operator ++()) i.operator =(operator ++(i)) > 运算符++ 调用之前的所有效果 $ c>。



2。 a [++ i] = i;



如果 a 是一个数组类型, i 是一个 int ,那么表达式还有几个部分:



(a) i

值计算

(b) ++ i

值计算

(c) ++ i 副作用,将新值存回 i



(d) a [++ i] ,它为由 +的值计算索引的 a 的元素返回 lvalue + i



(e)赋值的值计算,只是存储的值< / c>< / c>的值计算结果

(b) > ,将新值存储到数组元素 a b

同样,所有这些事情都会在之前进行排序。 (即它们都由语句的最后一个分号完成)



同样,由于 ++ i i + = 1 ,存储值的副作用 / c> )之前, $ b

数组索引的值计算 ++ i 是*顺序计算值计算 (d)。



值计算在赋值本身的值计算之前,顺序之前 >副作用。因此,在(f)之前(e)和(e)之前对序列进行测序。


$因此我们具有两个序列:(a) - >(d) - >(e) - >(f)和(c) - >(b) - > >(f)。



不幸的是,(a)和(c)之间没有排序。因此,对于值计算,存储 i 副作用 on i ,并且代码显示未定义的行为。这再次由C ++ 11标准的1.9p15给出。



如上所述,如果 i



规则



规则相对直接:


  1. 内置运算符的参数的值计算

    b
  2. 任何其他内置运算符的值计算是之前的排序。


  3. 内置逗号左侧的值计算 副作用运算符是在右侧的值计算 副作用之前进行排序

    >

  4. 完整表达式的所有值计算副作用下一个完整表达式。


  5. 函数调用的参数的值计算和<

  6. 之前的 顺序

    之前的 >
  7. 对于完整表达式中的任意两个函数调用,一个结果的值计算顺序到另一个,或反之亦然。如果没有其他规则指定排序,编译器可以选择



    因此在 a()+ b() a()顺序 b() $ c> b()顺序 a(),但没有规则。


  8. 如果有两个副作用修改同一个变量,


  9. 如果存在修改变量的副作用 另一方面,代码具有未定义的行为。


$

b $ b

I went through this excellent answer regarding Undefined Behaviour and Sequenced [Before/After] relations in C++11. I understand the binary relation concepts, but am missing what the new rules governing sequencing are.

For these familiar examples, how do the new sequencing rules apply?

  1. i = ++i;
  2. a[++i] = i;

More specifically, what are the new C++11 sequencing rules?

I am looking for some rules like (this one is completely made up)

The lhs of an '=' statement is always sequenced before the rhs, and is thus evaluated first.

In case these are available in the standard itself, can someone quote the same here? Thanks.

解决方案

The sequenced-before relationship, and the rules concerning it are a "tidying up" of the prior rules on sequence points, defined in a consistent way with the other memory model relationships such as happens-before and synchronizes-with so that it can be precisely specified which operations and effects are visible under which circumstances.

The consequences of the rules are unchanged for simple single-threaded code.

Let's start with your examples:

1. i = ++i;

If i is a built-in type such as int then there are no function calls involved, everything is a built-in operator. There are thus 4 things that happen:

(a) The value computation of ++i, which is original-value-of-i +1

(b) The side effect of ++i, which stores original-value-of-i +1 back into i

(c) The value computation of the assignment, which is just the value stored, in this case the result of the value computation of ++i

(d) The side effect of the assignment, which stores the new value into i

All of these things are sequenced-before the following full expression. (i.e. they are all complete by the final semicolon of the statement)

Since ++i is equivalent to i+=1, the side effect of storing the value is sequenced-before the value computation of ++i, so (b) is sequenced-before (a).

The value computation of both operands of an assignment is sequenced-before the value computation of the assignment itself, and that is in turn sequenced-before the side effect of storing the value. Therefore (a) is sequenced before (c), and (c) is sequenced-before (d).

We therefore have (b) -> (a) -> (c) -> (d), and this is thus OK under the new rules, whereas it was not OK under C++98.

If i was a class, then the expression would be i.operator=(i.operator++()), or i.operator=(operator++(i)), and all effects of the operator++ call are sequenced-before the call to operator=.

2. a[++i] = i;

If a is an array type, and i is an int, then again the expression has several parts:

(a) The value computation of i

(b) The value computation of ++i

(c) The side effect of ++i, which stores the new value back into i

(d) The value computation of a[++i], which returns an lvalue for the element of a indexed by the value computation of ++i

(e) The value computation of the assignment, which is just the value stored, in this case the result of the value computation of i

(f) The side effect of the assignment, which stores the new value into the array element a[++i]

Again, all of these things are sequenced-before the following full expression. (i.e. they are all complete by the final semicolon of the statement)

Again, since ++i is equivalent to i+=1, the side effect of storing the value is sequenced-before the value computation of ++i, so (c) is sequenced-before (b).

The value computation of the array index ++i is *sequenced-before` the value computation of the element selection, so (b) is sequenced-before (d).

The value computation of both operands of an assignment is sequenced-before the value computation of the assignment itself, and that is in turn sequenced-before the side effect of storing the value. Therefore (a) and (d) are sequenced before (e), and (e) is sequenced-before (f).

We therefore have two sequences: (a) -> (d) -> (e) -> (f) and (c) -> (b) -> (d) -> (e) -> (f).

Unfortunately, there is no ordering between (a) and (c). Thus a side effect which stores to i is unsequenced with respect to a value computation on i, and the code exhibits undefined behaviour. This is again given by 1.9p15 of the C++11 standard.

As above, if i is of class type then everything is fine, because the operators become function calls, which impose sequencing.

The rules

The rules are relatively straightforward:

  1. The value computations of the arguments of a built-in operator are sequenced-before the value computation of the operator itself.

  2. The side effects of a built-in assignment operator or preincrement operator are sequenced-before the value computation of the result.

  3. The value computation of any other built-in operator is sequenced-before the side effects of that operator.

  4. The value computation and side-effects of the left-hand side of the built-in comma operator are sequenced-before the value computation and side-effects of the right-hand side.

  5. All value computations and side effects of a full expression are sequenced-before the next full expression.

  6. The value computation and side effects of the arguments of a function call are sequenced before the first full expression in the function.

  7. The value computation and side effects of everything inside a function are sequenced-before the value computation of the result.

  8. For any two function calls in the full expression, either the value computation of the result of one is sequenced-before the call to the other, or vice-versa. If no other rule specifies the ordering, the compiler may choose.

    Thus in a()+b(), either a() is sequenced-before b(), or b() is sequenced-before a(), but there is no rule to specify which.

  9. If there are two side effects that modify the same variable, and neither is sequenced-before the other, the code has undefined behaviour.

  10. If there is a side effect that modifies a variable, and a value computation that reads that variable, and neither is sequenced-before the other, the code has undefined behaviour.

这篇关于在C ++ 11,如何确定什么是“排序前”的其他人?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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