Reputation: 3
I don't understand why my two expressions produce the same result even though the second expression calls f()
twice.
I am using gcc with C++20 enabled.
#include <iostream>
using namespace std;
int& f(int& i, string name);
int main() {
puts("\n-------------------------------------\n");
int x = 5;
/* expression one */
printf("the result of (f(x) += 1) is:--> %d\n", f(x, "one") += 1);
printf("x is: %d\n",x);
printf("********************\n");
x = 5;
/* expression two */
printf("the result is:--> %d\n", f(x, "two") = f(x, "three") + 1);
printf("x is: %d\n", x);
puts("\n-------------------------------------\n");
return EXIT_SUCCESS;
}
int& f(int& i, string name) {
++i;
printf("<%s> value of i is: %d\n", name.c_str(), i);
return i;
}
The output of my program is:
-------------------------------------
<one> value of i is: 6
the result of (f(x) += 1) is:--> 7
x is: 7
********************
<three> value of i is: 6
<two> value of i is: 7
the result is:--> 7
x is: 7
-------------------------------------
Upvotes: 0
Views: 180
Reputation: 36488
If we break expression 2 into separate steps it might become clearer what is happening:
f(x, "two") = f(x, "three") + 1;
Is equivalent to (though note the order of evaluation isn't guaranteed before c++17):
int b = f(x, "three") + 1;
int& a = f(x, "two");
a = b;
However as f(x)
returns a reference to x
, a
is also a reference to x
. Using this if we then expand the function calls we get:
int b = ++x + 1;
++x;
x = b;
Notice how the second ++x
is ignored, this is why it doesn't have the value you expect.
Upvotes: 3
Reputation: 19213
Note that this is undefined behaviour before (and correct after) C++17 which explicitly sequences evaluation of left, right sides including their side-effects.
f(x, "one") += 1
is evaluated as:
1
.i: 5->6
i
which holds 6.+=
by adding one to the returned reference, setting i: 6->7
.The expression is evaluated to ref to i
holding 7
.
f(x, "two") = f(x, "three") + 1
i: 5->6
i
which holds 6 now.1
-> right side is 7.i: 6->7
.i
which holds 7 now.=
by assigning the right side(7
) to left side(i
), setting i
to 7.The expression is evaluated to ref to i
holding 7
.
In the second expression it doesn't matter what happens to i
inside left f
call - if it returns i
ref, it will be set to 7
.
Upvotes: 1