New Sequence Points in C++11

前端 未结 2 2000
死守一世寂寞
死守一世寂寞 2020-12-30 15:19

With the new college year upon us.
We have started to receive the standard why does ++ i ++ not work as expected questions.

After just answering one

相关标签:
2条回答
  • 2020-12-30 15:46

    I don't think sequencing is relevant to your situation. The expression ++i++ is grouped as ++(i++), so:

    • If i is a built-in type, then this is invalid, since i++ is an rvalue.

    • If i is of user-defined type and the operators are overloaded, this is a nested function call, such as T::operator++(T::operator++(i), 0), and function arguments are evaluated before the function call is evaluated.

    0 讨论(0)
  • 2020-12-30 15:56

    The UB in those cases is based on [intro.execution]/15

    Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced. [...] The value computations of the operands of an operator are sequenced before the value computation of the result of the operator. If a side effect on a scalar object is unsequenced relative to either another side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

    For ++(++i): [expr.pre.incr]/1 states that ++i is defined as i+=1. This leads to [expr.ass]/1, which says

    In all cases, the assignment is sequenced after the value computation of the right and left operands, and before the value computation of the assignment expression.

    Therefore, for ++(++i), equivalent to (i+=1)+=1, the inner assignment is sequenced before the outer assignment, and we have no UB.


    [intro.execution]/15 has an example of UB:

    i = i++ + 1; // the behavior is undefined
    

    The case here is a bit different (thanks to Oktalist for pointing out a pre/postfix mistake here). [expr.post.incr]/1 describes the effects of postfix increment. It states:

    The value computation of the ++ expression is sequenced before the modification of the operand object.

    However, there is no requirement on the sequencing of the side effect (the modification of i). Such a requirement could also be imposed by the assignment-expression. But the assignment-expression only requires the value computations (but not the side effects) of the operands to be sequenced before the assignment. Therefore, the two modifications via i = .. and i++ are unsequenced, and we get undefined behaviour.

    N.B. i = (i = 1); does not have the same problem: The inner assignment guarantees the side effect of i = 1 is sequenced before the value computation of the same expression. And the value is required for the outer assignment, which guarantees that it (the value computation of the right operand (i = 1)) is sequenced before the side effect of the outer assignment. Similarly, i = ++i + 1; (equivalent to i = (i+=1) + 1;) has defined behaviour.


    The comma operator is an example where the side effects are sequenced; [expr.comma]/1

    Every value computation and side effect associated with the left expression is sequenced before every value computation and side effect associated with the right expression.

    [intro.execution]/15 includes the example i = 7, i++, i++; (read: (i=7), i++, i++;), which is defined behaviour (i becomes 9).

    0 讨论(0)
提交回复
热议问题