#include <iostream>
int& addOne(int& x)
{
x = 1;
return x;
}
int main()
{
int x {5};
addOne(x) = x;
std::cout << x << ' ' << addOne(x);
}
I'm currently in the middle of learning about lvalues and rvalues and was experimenting a bit, and made this which seems to be getting conflicting results. https://godbolt.org/z/KqsGz3Toe produces an out put of "5 6", as does Clion and Visual Studio, however https://www.onlinegdb.com/49mUC7x8U produces a result of "6 7"
I would think that because addOne is calling x as a reference, it would explicitly change the value of x to 6 despite being called as an lvalue. What should the correct result be?
CodePudding user response:
Since C 17 the order of evaluation is specified such that the right-hand side of assignment is evaluated first and that the << operator is evaluated left-to-right.
So in
addOne(x) = x;
first the value of the right-hand side is evaluated, yielding 5. Then the function addOne is called and it doesn't matter what it does with x since it returns a reference to it, to which the right-hand value 5 is assigned.
Then in the line
std::cout << x << ' ' << addOne(x);
we first evaluate and output x, resulting in 5, and then call addOne, resulting in 6.
The output 5 6 is the only correct one since C 17.
Before C 17, the evaluation order of the two sides of the assignment operator was unsequenced.
Having a scalar modification unsequenced with a value computation on the same scalar (on the right-hand side of your assignment) causes undefined behavior normally.
But since you put the increment of x into a function, an additional rule saying that the execution of a function body is merely indeterminately sequenced with other evaluations in the calling context saves this. It means that the line wont have undefined behavior anymore, but the order in which the evaluations of the two sides of the assignment happen could be either left-first or right-first.
This means we won't know whether x is evaluated first and then addOne(x) or the other way around.
Therefore after the line, x may be 5 or 6.
Then in the line
std::cout << x << ' ' << addOne(x);
pre-C 17 the same issue applied. The evaluations of the arguments to << were indeterminately sequenced, rather than left-to-right and so addOne(x) could be evaluated before the left-hand x.
Therefore possible program output could be either of the following:
5 6
6 6
6 7
7 7
You can specify to use C 17 (or newer versions like C 20) with the -std=c 17 flag to the compiler if you are using GCC or Clang and /std:c 17 if you are using MSVC. Which standard version is chosen by-default depends on the compiler and compiler version.
