Compound assignment

When we use the compound assignment, the left-hand operand is evaluated only once. If we use an ordinary assignment, that operand is evaluated twice: once in the expression on the right-hand side and again as the operand on the left hand.
 
  sum = sum + val;

 
  sum += val;


Everyone says that these two assignments are equivalent but my book says that the first assignment does a bit more work than the other one. Are they working then differently? And if the quote is correct then why does sum evaluate twice in the first assignment?
The expressions are equivalent only if sum is of a basic type (int, float, pointer, etc.). This is no longer true if sum is an object and its corresponding operators are overloaded.
These expressions can't be equivalent if one expression does more work than the other one. Still can't understand it.
Once again: the expressions are equivalent (i.e. the compiler transforms them into the exact same machine code) if sum is of a basic type.
If sum is an object, then its operator overloads may be implemented in such a way that one expression does more work than the other. This is because if sum is an object, then the fully expanded expressions are
sum.operator=(sum.operator+(val));

sum.operator+=(val);
It's one function call versus two function calls.
Last edited on
> Everyone says that these two assignments are equivalent

These two are equivalent except that:

in e1 += e2, the expression e1 is evaluated only once.

in e1 = e1 + e2, the expression e1 is evaluated twice.


> but my book says that the first assignment does a bit more work than the other one.

The first need not necessarily do more work than the second; the "as-if" rule applies.
http://en.cppreference.com/book/as_if

If sum is a scalar (say an int), the observable behaviour of a program with sum = sum + 6 ; is identical to one in which that statement was replaced with sum += 6 ;. Compilers are allowed to (and they do) generate the same code for both.

e1 += e2 ; and e1 = e1 + e2 ; would be different if the evaluation of e1 has observable side-effects:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>

int main()
{
    int sum = 7 ;
    const int val = 6 ;

    std::cout << "simple assignment: " ;
    ( ( std::cout << "evaluate sum    " ), sum ) = ( ( std::cout << "evaluate sum    " ), sum ) + val ;
    // simple assignment: evaluate sum    evaluate sum

    sum = 7 ;
    std::cout << "\n\ncompound assignment: " ;
    ( ( std::cout << "evaluate sum    " ), sum ) += val ;
    // ompound assignment: evaluate sum
}

http://coliru.stacked-crooked.com/a/50af3fc8f7daaacb
Sorry, I might have used the wrong word (equivalent) to describe my problem. I should have asked this question in this way. Why is e1 evaluated only once in the compound assignment but in ordinary assignment e1 is evaluated twice if they are "completely same?"
The expressions are not "completely the same". That's just false. What you can say is what I said above, that they're equivalent under certain conditions
> Why is e1 evaluated only once in the compound assignment
> but in ordinary assignment e1 is evaluated twice if they are "completely same?"

Because they are not "completely same".

a = b + c ; requires the right hand side b + c to be evaluated and the left hand side a to be evaluated.
Evaluation of b + c requires b to be evaluated and c to be evaluated.

a = a + c ; requires the right hand side a + c to be evaluated and the left hand side a to be evaluated.
Evaluation of a + c requires a to be evaluated and c to be evaluated.
(a is evaluated twice, once for the right hand side and once for the left hand side.)

Even though a = a + c ; and a += c ; are not "completely same", if the observable behaviour of the program is indistinguishable with either construct, the implementation is allowed (by the "as-if" rule) to replace one construct with the other.

The "as-if" rule always applies; for scalars as well as for user-defined types.
An implementations is allowed to generate the same code for the three functions
foo(), bar() and foobar() - because their observable behaviour is the same.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
struct A
{
    int i ;
    A& operator+= ( int v ) { i += v ; return *this ; }
};

A operator+ ( A a, int v ) { a.i = a.i +v ; return a ; }

int foo( A a )
{
    a += 6 ;
    return a.i ; 

    /*
        leal    6(%rdi), %eax
        ret
    */
}

int bar( A a )
{
    a = a + 6 ;
    return a.i ; 

    /*
        leal    6(%rdi), %eax
    	ret
    */
}

int foobar( A a )
{
    A temporary_object = operator+( a, 6 ) ;
    a.operator= (temporary_object) ;
    return a.i ;

    /*
        leal    6(%rdi), %eax
        ret
    */
}

http://coliru.stacked-crooked.com/a/fc30442ad5018c22
Topic archived. No new replies allowed.