Search code examples
c++operator-precedence

why i = ++i + 2 is undefined behavior?


I've read something about order of evaluation and I understand some mistakes caused by order of evaluation.

My basic rule comes from a text and example:

  • Order of operand evaluation is independent of precedence and associativity.
  • In most cases, the order is largely unspecified.

So for expression like this: int i = f1() * f2();

f1 and f2 must be called before the multiplication can be done. After all, it is their results that are multiplied. However, we have no way of knowing whether f1 will be called before f2 or vice versa.

Undefined behavior examples:

int i = 0;
cout << i << " " << ++i << endl; 

How I understand: I treat i and ++i as a function. I don't know which evaluates first, so the first i could be 0 or 1 and (the rule) makes sense.


while(beg != s.end())
    *beg = toupper(*beg++);  //Just another example.

I think the key to understand this is to treat each operand as a "evaluation unit", and one don't know order of evaluation within these units but can know order in every single unit.

But for i = ++i + 2 reference here, Why is it wrong? I can't explain with my own conclusion.

The left i is used as a lvalue and not a pointer. ++i simply rewrite the original value and doesn't change the storage address. What could be wrong if it evaluates first or latter? My rule fails here.

Quite long but try to provide enough background info, thank for your patience.


I don't know sequence point which is mentioned frequently in answers.. So I think I need to read something about it first. Btw, the debate is not very helpful, for a newbie simply want to know why is it considered wrong, like before C++11?


I find this answer Undefined behavior and sequence points explain well why i = ++i + 2 is undefined behaviour before C++11


Solution

  • C++11 has new sequencing rules. In particular, for a pre-increment (++i) the side effect (writing the new value) is sequenced-before the further use of the new, incremented value. Since the assignment i= is sequenced-after the evaluation of its right-hand side, this means the write ++i is transitively sequenced-before the write i=(++i + 2)

    It would be another matter for i=(i++ + 2). For post-increment, the side effect is sequenced-after, which means the two assignments are no longer sequenced relatively to each other. That IS undefined behavior.