1

Consider following code:

#include <iostream>

int main()
{
    int i = 0;
    std::cout << ++i << ' ' << --i << std::endl;
}

In his "C++17 The Complete Guide" book Nicolai Josuttis writes that before C++17 this particular example might produce unpredictable results. Both 1 0 and 0 1 might be produced but what's more 0 0 is also a possible output. I don't get why the third sequence should be considered as possible. Either ++i or --i should be evaluated before the second value is evaluated which by definition cannot produce two zeros, shouldn't it?

Amolgorithm
  • 697
  • 2
  • 20
Mati
  • 753
  • 4
  • 20
  • @Amolgorithm That's pre-increment, not post-increment if you really want to add such tags. – Yksisarvinen Jul 28 '23 at 11:44
  • 2
    Absolutley just a guess: four things are happening, take the value of i, incriment i, take the value of i, decrement i. I don't think the order of *any* of those things is defined - so while it does seem likely that they would *at least* happen in pairs, I think a "correct" C+++ compiler is allowed to do them in truly any order, even take the value of i twice first. – Jay Jul 28 '23 at 11:49
  • The evaluation order of sub-expressions in between `<<` is not defined. – Pepijn Kramer Jul 28 '23 at 11:51
  • 1
    Replace `++i` with "increment `i`, read `i`", same for `--i`, then do as follows: increment `i`, decrement `i`, read `i`, read `i`. Then remove increment-decrement as an optimization if you're up to it. There were no guarantees that sub-expressions and their side effects are not interleaved. Fun effects are still possible with C++17, though, but require more convoluted examples. – yeputons Jul 28 '23 at 11:51

1 Answers1

5

Before C++17, the 0 0 outcome was possible roughly like this.

  1. ++i is evaluated. i now stores 1. The result of this expression (which, importantly, is an l-value reference to i, not the r-value 1) is set aside as an argument to the << operator.
  2. --i is evaluated. i now stores 0. The result of this expression (which, importantly, is an l-value reference to i, not the r-value 0) is set aside as an argument to the << operator.
  3. << operators are evaluated, where both arguments are references to i which has value 0.
yuri kilochek
  • 12,709
  • 2
  • 32
  • 59