1

The output of this piece of code is

21

I am unable to explain it to myself. My thinking (what I learned) is that an implicit copy constructor is called (triggered by the assignment) and all elements are copied bit by bit. However this does not apply to external elements, like the private variable val, which is a pointer. So b has a different pointer, but it is pointing to the same element.

So I expected the result to be

22

That is .get() is called twice by a and b and thus the dereferenced pointer value should be 1 (after the first get()) and then 2 (after the second get()). Finally the values are written to the console output.

C++ code:

#include <iostream>
using namespace std;

class A {
    int *val;
public:

    A() {
        val = new int;
        *val = 0;
    }

    int get() {
        return ++(*val);
    }
};

int main() {
    A a, b = a;
    cout << a.get() << b.get();
    return 0;
}
Ely
  • 9,920
  • 3
  • 38
  • 60
  • Why would you get the same return value from the two `get`s? Calling it again won't magically change the value returned by the first call. – molbdnilo Jun 08 '15 at 11:33
  • I thought the get()s are evaluated first ant then printed to the console output. I guess I am wrong with that, considering the answers. Still trying to read and digest. – Ely Jun 08 '15 at 11:41
  • 1
    So you _actually_ expected the result to be `12`, not `22`? That's because you made a false assumption about operand evaluation order. – Lightness Races in Orbit Jun 08 '15 at 11:41
  • Well, I mean that the whole output would be done at the end. I don't know why, but I believed the order to be like that: the first get() increases the value, then the second get() increases the value and the it is printed and would be 22. I understand now that I am completely wrong with that. – Ely Jun 08 '15 at 11:47

4 Answers4

2

When using cout, evaluation of a.get() and b.get() is done in no specific order. Thus, in your example b.get() is evaluated first (to 1), and then a.get() (to 2), and then "21" is printed on screen.

Noel
  • 640
  • 5
  • 14
  • Can you provide a reference of your statement? This piece of code was in an assessment of the C++ institute. And if the order is undefined I wonder how can they know exactly the output? – Ely Jun 08 '15 at 11:25
  • @Elyasin see [link](http://stackoverflow.com/questions/2129230/cout-order-of-call-to-functions-it-prints) for example – Noel Jun 08 '15 at 11:26
  • @Elyasin: Who's "they"? If you mean the programmer, then "they" _can't_. That's why you should evaluate the function call in a variable first. – Lightness Races in Orbit Jun 08 '15 at 11:42
  • It is an online training from the C++ Institute and that piece of code was part of an online assessment. So "they" means the guys who developed the C++ course and the assessment. – Ely Jun 08 '15 at 11:48
1

Your problem is one of sequence points: std::cout << a.get() << b.get(); has no strict defined evaluation order for a.get() and b.get().

See this answer here for all the explanations.

Community
  • 1
  • 1
BeyelerStudios
  • 4,145
  • 17
  • 35
1

First the get function is called for object b and then it is call for the object a, hence giving a o/p of 2 1

(gdb) s
main () at so2.c++:20
20          cout << a.get() << b.get();
(gdb) p &a
$6 = (A *) **0x7fffffffd0f0**
(gdb) p &b
$7 = (A *) *0x7fffffffd0e0*
(gdb) s
A::get (this=*0x7fffffffd0e0*) at so2.c++:14
14              return ++(*val);
(gdb) p *val
$8 = 0
(gdb) n
15          }
(gdb) p *val
$9 = 1
(gdb) s
A::get (**this=0x7fffffffd0f0**) at so2.c++:14
14              return ++(*val);
(gdb) s
15          }
(gdb) p *val
$10 = 2

From the above debuggging session we can see the flow and behavior.

Rndp13
  • 914
  • 1
  • 16
  • 31
1

This is what the code actually does:

cout.operator<<( a.get() ).operator<<( b.get() );

or

operator<<( operator<<( cout, a.get() ), b.get() );

(I can't get the latter to compile due to overloading issues, but it does happen behind the scenes)

Which means that the code evaluates std::endl before b.get(), and b.get() before a.get(). So b.get() increases val's pointed value by 1 and then returns 1, and a.get() increases val's pointed value by 1 and returns 2. The operators are called in the expected order after the parameters are evaluated. I'd guess this is compiler dependent, but I ran your code and got the 21 as well.

In this case you are using an implicit copy constructor. What it does is copy the memory of your instance a to instance b. (As you said, byte by byte)

So b now owns its own pointer which holds the same value as a's pointer, that is to the same address. Since you increase the value on get(), the returned value would never be the same so you would never get 22 as a result.

Edit: You didn't actually use std::endl, it's my habit.

aslg
  • 1,886
  • 1
  • 11
  • 19