3

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

Rick
  • 7,007
  • 2
  • 49
  • 79
  • Possible duplicate of [New Sequence Points in C++11](https://stackoverflow.com/questions/19069681/new-sequence-points-in-c11) – M.M Jun 19 '18 at 09:52

2 Answers2

4

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.

MSalters
  • 173,980
  • 10
  • 155
  • 350
-3

Your two "subfunctions" in i = ++i + 2 are an explicit assignment made by the = operator and an implicit assignment done by the ++ operator.

The preincrement operator is defined to return an incremented value of the variable, and this definitely shall be used for addition (performed by the + operator). However, it was not defined, when the incremented value should be stored back into i.

As a result, it was undefined whether the final value of i is old_i incremented plus 2 or just old_i incremented.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
CiaPan
  • 9,381
  • 2
  • 21
  • 35
  • "However, it was not defined, when the incremented value should be stored back into i" before C++11 yes but not after. – Rakete1111 Jun 19 '18 at 09:30
  • @CiaPan - alas you and I were incorrect on this. (I've since deleted my answer). Trivial edit to convert +1 to -1. – Bathsheba Jun 19 '18 at 09:42
  • There is no such thing as "undefined whether the value was X or Y". If the value could be X or Y then that situation is called *unspecified behaviour*, which this is not. *Undefined behaviour* means anything whatsoever can happen. Also you speak in the past tense but you do not specify when the behaviour changed from undefined to defined. – M.M Jun 19 '18 at 09:52
  • @M.M At least three answers and comments before mine described _when_ that changed, so I didn't need to specify that once again. My aim was to display where the 'undefined' status comes from. – CiaPan Jun 19 '18 at 10:30