Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Possible UB? Getting different results from different sources

#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?

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

>Solution :

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 right-hand side) 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 only indeterminately sequenced with other evaluations in the calling context removes this source of undefined behavior.

This means however, that 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.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading