Sequenced relationships and the rules related to this are the βorderingβ of previous rules about sequence points that are consistently consistent with other relationships of the memory model, such as occurring earlier and synchronized, you can precisely determine which operations and effects are visible under what circumstances.
The consequences of the rules are not changed for simple single-threaded code.
Start with your examples:
1. i = ++i;
If i is a built-in type, such as int , then there are no functions involved, all this is a built-in operator. So there are 4 things:
(a) Calculation of the value ++i , which is the original value-i +1
(b) A side effect of ++i that keeps the original value of -i +1 back to i
(c) Calculation of the assignment value, which is only the stored value, in this case, the result of calculating the value ++i
(d) A side effect of the assignment that stores the new value in i
All these things are sequenced - before the next full expression. (i.e. all of them are terminated by an operator endpoint)
Since ++i equivalent to i+=1 , the side effect of storing the value is sequenced - before calculating the value of ++i , therefore (b) is sequenced before (a).
The calculation of the values ββof both assignment operands is sequenced - before calculating the value of the assignment itself and, in turn, is ordered - before the side effect of storing the value. Therefore, (a) sequenced to (c) and (c) sequenced to (g).
Therefore, we have (b) β (a) β (c) β (d), and this, therefore, is OK in accordance with the new rules, while in C ++ 98 there was no OK.
If i was a class , then the expression would be i.operator=(i.operator++()) or i.operator=(operator++(i)) , and all the effects of calling operator++ sequenced - before calling operator= .
2. a[++i] = i;
If a is an array type and i is int , then again the expression has several parts:
(a) Calculation of i
(b) Calculation of ++i
(c) A side effect of ++i that saves the new value back to i
(d) Computing the value of a[++i] , which returns the value of l for the element a , indexed by computing the value of ++i
(e) The calculation of the assignment value, which is only the stored value, in this case is the result of calculating the value of i
(f) A side effect of an assignment that stores a new value in an array element a[++i]
Again, all these things are sequenced - before the next full expression. (i.e. all of them are terminated by an operator endpoint)
Again, since ++i equivalent to i+=1 , the side effect of storing the value is sequenced - before calculating the value of ++i , therefore (c) is sequenced before (b).
The calculation of the index value of the ++i array is * sequenced-before` the calculation of the element selection value, therefore (b) is sequenced-up to (d).
The calculation of the values ββof both assignment operands is sequenced - before calculating the value of the assignment itself and, in turn, is ordered - before the side effect of storing the value. Therefore, (a) and (d) are sequenced to (e) and (e) sequenced to (f).
Therefore, we have two sequences: (a) β (d) β (e) β (f) and (c) β (b) β (d) β (e) β (f).
Unfortunately, there is no order between (a) and (c). Thus, the side effect that is stored before i does not affect the calculation of the value on i , and the code demonstrates undefined behavior. This is again given by 1.9p15 of the C ++ 11 standard.
As above, if i has a class type, then everything is fine, because operators become calls to functions that impose a sequence.
rules
The rules are relatively simple:
The calculation of the values ββof the arguments of the built-in operator is sequenced - before calculating the value of the operator itself.
Side effects of the built-in assignment operator or preincrement operator are sequenced - before calculating the result value.
The calculation of the values ββof any other built-in operator is sequenced - before the side effects of this operator.
The calculation of values and side effects of the left side of the built-in comma operator are sequenced - before calculating the values and side effects of the right side.
All calculation calculations and side effects of the full expression are sequenced - before the next full expression.
The calculation of the value and side effects of the function call arguments are sequenced before the first full expression in the function.
The calculation of the value and side effects of everything inside the function are sequenced - before calculating the value of the result.
For any two function calls in full expression, either the calculation of the result value of one is sequenced - before calling the other, or vice versa. If no other rule indicates the order, the compiler can choose.
Thus, in a()+b() either a() sequenced to b() or b() sequenced to a() , but there is no rule to indicate which one.
If there are two side effects that change the same variable, and none of them are sequenced - before the other, the code has undefined behavior.
If there is a side effect that modifies a variable and calculates the value that reads this variable, and none of them are sequenced - before the other, the code has undefined behavior.