Hinata Chikao
Hinata Chikao

Reputation: 3

What is the difference between x+=x and x = x +y in C++

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

Answers (2)

Alan Birtles
Alan Birtles

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

Quimby
Quimby

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. Evaluate right side to 1.
  2. Evaluate left side:
    1. Set i: 5->6
    2. Return ref to i which holds 6.
  3. Evaluate += 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
  1. Evaluate right side:
    1. Set i: 5->6
    2. Return ref to i which holds 6 now.
    3. Add 1 -> right side is 7.
  2. Evaluate left side:
    1. Set i: 6->7.
    2. Return ref to i which holds 7 now.
  3. Evaluate = 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

Related Questions