C++ – Is int a = ++i + ++i Undefined Behavior?

c++c++17language-lawyersequencingundefined-behavior

Consider the following code:

int main(){
  int i = 0;
  int a = ++i + ++i;
}

I can't find any information that says that the operands of + are unsequenced. So according to the standard, the sequence of operands of binary + are indeterminately sequenced.

[intro,excution]/15

Given any two evaluations A and B, if A is sequenced before B (or, equivalently, B is sequenced after A), then the execution of A shall precede the execution of B. If A is not sequenced before B and B is not sequenced before A, then A and B are unsequenced. [ Note: The execution of unsequenced evaluations can overlap.  — end note ]

Evaluations A and B are indeterminately sequenced when either A is sequenced before B or B is sequenced before A, but it is unspecified which.[ Note: Indeterminately sequenced evaluations cannot overlap, but either could be executed first.  — end note ]

The quote means that the evaluation of A can occur before B or the evaluation of B can occur before A. And the execution of unsequenced evaluations can overlap, whereas indeterminately sequenced evaluations cannot overlap, which are different.

We know the modification of i always occurs before value computation of i due to prefix ++.

Then according to the rules:

Evaluation of an expression (or a subexpression) in general includes both value computations (including determining the identity of an object for glvalue evaluation and fetching a value previously assigned to an object for prvalue evaluation) and initiation of side effects

If a side effect on a memory location is unsequenced relative to either another side effect on the same memory location or a value computation using the value of any object in the same memory location, and they are not potentially concurrent, the behavior is undefined

So regardless of whether the evaluation of A is before B or the converse, there are no side effects related to corresponding value computation or side effect for ++i + ++i;. Because indeterminately sequenced evaluations cannot overlap, one of the two evaluation must be completely executed before the other. The evaluation includes both value computation and side effect. Therefore, one increment to i is evaluated before the other.

Unsequenced evaluations, however, follow different rules, so the confusion will be resolved if the evaluations of operands of binary + are unsequenced rather than indeterminately sequenced. If I missed something in the standard in the analysis above, please correct me.

Update

I found the following sentence, which seems to suggest that the evaluations are unsequenced:

Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced.

However, I don't know how to understand the sentence correctly. I came up with two interpretations:

For an operator A, the evaluations of the operands of A are
unsequenced with each other; for an expression B, the evaluations of
the subexpressions of B are unsequenced with each other.

and

Take evaluations of operands of individual operators as A. Take
evaluations of subexpressions of individual expressions as B. A is
unsequenced with B.

Which interpretation is correct?

Best Answer

The standard text seems1 to imply that the behavior is undefined.

  • in <a>+<b> the evaluations of <a> and <b> are unsequenced2,3
  • the two parts have side effect that affect the same memory location

(1) This part is in my opinion unambiguous and clear, but I'm not sure there are not other parts that are saying the opposite or that some higher level concept (e.g. what is the execution of a program) is not logically broken because of contradicting rules. Given the complexity of C++ I would actually be quite surprised of no errors being present.

(2) In case of an overloaded operator+ they would be indeterminately sequenced (as the rules are the same as for a function call, thus NOT undefined behavior: 8.5.1.2[5] of N4713 says "The postfix-expression is sequenced before each expression in the expression-list and any default argument. The initialization of a parameter, including every associated value computation and side effect, is indeterminately sequenced with respect to that of any other parameter") but for native ints this does not apply and the behavior is undefined.

(3) The text says "Except where noted, evaluations of operands of individual operators and of subexpressions of individual expressions are unsequenced". Of course for unary operators the question is irrelevant (there is no ordering to talk about) and for the ternary ?: operator there are special sequencing rules. The part about "subexpressions" is to cover cases like a[++i][++i] where a is for example a char **: in this case the two identical sub-expressions ++i are unsequenced and with side effects modifying the same memory location and thus undefined behavior. I think the paragraph is actually more complex than necessary because operands of an operator are also subexpressions of an expression thus the last part was sufficient.