在C ++ 11,如何确定什么是“排序前”的其他人? [英] In C++11, how to determine what is 'sequenced before' others?
问题描述
我参与了有关未定义行为和序列[之前/之后]的 这个出色的答案 ,关系在C ++ 11。
对于这些熟悉的示例,新顺序是如何实现的?规则适用?
-
i = ++ i;
-
a [++ i] = i;
更具体来说,新的C ++ 11排序规则是什么?
我正在寻找一些规则)
'='
lhs
/ code>语句总是在rhs
之前排序,因此首先计算。
b $ b
如果这些在标准本身可用,有人可以在这里报价相同吗?感谢。
之前的顺序关系,关于它的规则是整理与先前的规则关于序列点的定义,以与其他存储器模型关系一致的方式定义,诸如发生在之前和与同步以便可以精确地指定
对于简单的单线程代码,规则的后果不会改变。
让我们从你的例子开始:
1。 i = ++ i;
如果 i
一个内置的类型如 int
那么没有涉及的函数调用,一切都是内置的运算符。因此,有4种情况发生:
(a) ++ i $ c的值计算 $ c>,即
+1
(b) ++ i
的副作用,其存储原始值的 +1 返回
i
++ i
的值计算结果的值,
(d)作业的副作用,将新值储存到 i
所有这些都是顺序之前的完整表达式。 (即它们都由语句的最后一个分号完成)
由于 ++ i
code> i + = 1 ,存储值的副作用是顺序 > (a)之前
<
赋值的两个操作数的值计算在赋值本身的值计算之前进行排序,依次存储值的次序之前。因此,(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
规则
规则相对直接:
-
内置运算符的参数的值计算
。 b 任何其他内置运算符的值计算是之前的排序。
内置逗号左侧的值计算 和 副作用运算符是在右侧的值计算 和副作用之前进行排序
>完整表达式的所有值计算和副作用下一个完整表达式。
函数调用的参数的值计算和<
对于完整表达式中的任意两个函数调用,一个结果的值计算是顺序到另一个,或反之亦然。如果没有其他规则指定排序,编译器可以选择
因此在 a()+ b()
, a()
是顺序 b()
$ c> b()是顺序 a()
,但没有规则。
如果有两个副作用修改同一个变量,
如果存在修改变量的副作用 另一方面,代码具有未定义的行为。
$
b $ bI 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?
i = ++i;
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 therhs
, 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:
The value computations of the arguments of a built-in operator are sequenced-before the value computation of the operator itself.
The side effects of a built-in assignment operator or preincrement operator are sequenced-before the value computation of the result.
The value computation of any other built-in operator is sequenced-before the side effects of that operator.
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.
All value computations and side effects of a full expression are sequenced-before the next full expression.
The value computation and side effects of the arguments of a function call are sequenced before the first full expression in the function.
The value computation and side effects of everything inside a function are sequenced-before the value computation of the result.
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()
, eithera()
is sequenced-beforeb()
, orb()
is sequenced-beforea()
, but there is no rule to specify which.If there are two side effects that modify the same variable, and neither is sequenced-before the other, the code has undefined behaviour.
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屋!