1
#include<iostream>
using namespace std;

int& add() {

    static int a;
    a++;
    cout<<"\na="<<a;
    return a;
}

int main {

   int x,y,m;
   int &z = add(); //it behaves as a reference to "a" which is a static variable
   x=add();//why does it work correctly
   y=add();//why does it work correctly
   z++;
   m=add();//why does it work correctly
   cout<<"\nx="<<x<<"\ny="<<y<<"\nz="<<z<<"\nm="<<m;
   return 0;
}

output:
a=1
a=2
a=3
a=5
x=2
y=3
z=5
m=5

What happens exactly internally for x,y,m & z

cpx
  • 17,009
  • 20
  • 87
  • 142
Abhineet
  • 6,459
  • 10
  • 35
  • 53
  • 1
    If I ever saw this in a real program ... *rips eyes out of sockets* – Marlon Jul 05 '11 at 06:41
  • 1
    Just a simple question, what were you expecting from the above code? You already have a couple of answers that explain what is going on, but for the future, consider that it is easier for others to explain what your misconception is if you actually state it. *why does `x` get value `2` and doesn't get incremented later?* or whatever it is that does not seem intuitive to you. – David Rodríguez - dribeas Jul 05 '11 at 07:33
  • I dont have doubt on the above code as i myself written it with the comment. Doubt is why it doesnot throw error for x=add(),y=add() & m=add() since return type of add is int& – Abhineet Jul 05 '11 at 08:10
  • I have one more doubt if i make return type as "int" for the above problem then it throws error for int &z=add() Why does it do when it just return the value "a" – Abhineet Jul 05 '11 at 08:30

7 Answers7

3
int main{
    int x,y,m;      // declare three ints:  x,y,m, all unassigned
    int &z = add(); // a is incremented to 1, z is a reference to a
    x=add();        // add() returns a reference to a, x copies the value of a
    y=add();        // same as above
    z++;            // increments a, since z is a reference to a
    m=add();        // same as x and y, copies the value of a
    cout<<"\nx="<<x<<"\ny="<<y<<"\nz="<<z<<"\nm="<<m;
    return 0;
}

so you call add() three times in a row, which increments a to 1, 2, 3 (and prints the value each time.

z is a reference to the real a.

x, y, and m are copies of the value of a when the assignment was made. So x is 2, y is 3, we skip 4 by doing z++, and then m is 5.

Tim
  • 8,912
  • 3
  • 39
  • 57
3
int &z = add();

z is a reference to the static variable a. From now on, a and z are synonym. Both of them point to same memory location.

int x;
x = add();

x is an independent memory location. Because of the assignment, x will hold whatever add() returns at the point of calling. This is how y andm also works.

Donotalo
  • 12,748
  • 25
  • 83
  • 121
2

x, y, and m are just variables, so they get whatever value is in a at the time add is called, and that's it. If you were to change the values of any of those variables, it would not affect the value of a. Since z is a reference, it is a "pointer" (in a sense) to the static a variable, so changing z will actually change a.

Jim Buck
  • 20,482
  • 11
  • 57
  • 74
2

A reference is another name, an alias, for some object. It acts like if it was the object.

When add() returns a reference to a, it behaves like if the returned value was a.

So the code

x = add();

behaves like it had been

a++;
x = a;

So it captures the value a has at that moment.

On the other hand, the code

int& z = add();

behaves just like

a++;
int& z = a;

Where z becomes another name for a. Using a or z from now on doesn't matter, it means the same. There is still only one value, but the value has two names. We can use either one to to read it or update it.

It's just like when we use Bob to refer to a guy named Robert - another name for the same thing.

Bo Persson
  • 90,663
  • 31
  • 146
  • 203
  • Thanks for your answer. This was my actual doubt because i have kept return type as int& and still it was working good for x=add(),y=add() & m=add()... Thanks once again – Abhineet Jul 05 '11 at 08:17
  • I have one more doubt if i make return type as "int" for the above problem then it throws error for int &z=add(); Why does it do when it just return the value "a". – Abhineet Jul 05 '11 at 08:24
  • 1
    Because the `int` return value is a temporary that goes away at the end of the statement. You cannot have a reference to that, when it goes away. When not a reference, it doesn't return `a` anymore, but `a`'s value. :-) – Bo Persson Jul 05 '11 at 08:31
1

I believe this is how it works:

References used in context where (a value of) the referenced type is needed are implicitly dereferenced. This includes (among others):

  • assignment to a variable
  • passing function arguments declared by value
  • passing function return values declared by value

In the above contexts, a copy of the referenced value is created.

Wherever a reference is needed, they are treated as references (obviously not dereferenced.) This includes:

  • initializing a reference of compatible type
  • passing function arguments declared by reference
  • passing function return values if declared by reference

In these contexts, no copy of the referenced value is created. The new reference is just a new alias for the existing value.

The syntax for both of the above contexts is the same, so it requires some effort to see what's going on.

Rafał Dowgird
  • 43,216
  • 11
  • 77
  • 90
1

A reference is just a constant pointer, in the sense that you can change the pointed object but you cannot make it to point to something else.

What C++ does is just saving you from adding pointing de-referencing syntax (unary *) when you need the value and allows using . instead of -> to access members of the pointed-to structured type.

Note that there is a common anti-pattern in C++ that uses const X& as if that was a smarter way than just X for function parameters. Please never forget that a reference is basically a pointer so the pointed object may change or even disappear while being used (const doesn't mean the object doesn't change, just that you cannot change it using that reference).

See this answer for a more detailed description of why you should pay attention when using references instead of values.

Every time you see a reference you should think at least a bit if the object is going to live enough and/or mutate while you are using it. In your case the referenced object is a function static, therefore there are no problems with lifetime (function static objects come into existence the first time you enter the scope where they are defined and live until the end of the program).

Translating your code to what really happens (pointer fiddling) you get

#include<iostream>
using namespace std;

int* add() {
    static int a;
    a++;
    cout << "\na=" << a;
    return &a; // we're returning a pointer to our static variable
}

int main(int argc, const char *argv[]) {
   int x,y,m;
   int *z = add(); // points to "a" which is a static variable
   x = *add();     // just get the current value of (incremented) a
   y = *add();     // same here, of course now different from x
   (*z)++;         // incrementing a from outside the function (we've a pointer!)
   m = *add();     // once again just reading current incremented value
   cout << "\nx=" << x << "\ny=" << y<< "\nz=" << (*z) << "\nm=" << m;
   return 0;
}
Community
  • 1
  • 1
6502
  • 112,025
  • 15
  • 165
  • 265
1

Ok, let's dissect this small program

int& add() 
{
   static int a;
   a++;
   cout<<"\na="<<a;
   return a;
}

static int a declares a variable. Static in this context means that there is only on place to store a and that place is used whenever add is called. So a is like a global variable that can only be accessed inside add.

The return value is a reference. Most compiler use pointer internally to represent reference. What you can see here is that a reference to the static variable a is returned. Anyone can change a once he obtained the reference.

The a++ and the cout is straightforward - no further comments here.

int main{
    int x,y,m;      // declare three ints:  x,y,m, all unassigned
    int &z = add(); // a is incremented to 1, z is a reference to a
    x=add();        // add() returns a reference to a, x copies the value of a
    y=add();        // same as above
    z++;            // increments a, since z is a reference to a
    m=add();        // same as x and y, copies the value of a
    cout<<"\nx="<<x<<"\ny="<<y<<"\nz="<<z<<"\nm="<<m;
    return 0;
}

int &z = add(); calls add - which means that a is incremented. z is now an alias for the static variable a since it uses the reference. x=add(); increment a again but now copy the value of a since x is not of type int& but of type int. y - same. z++: since z is an alias for a - increment a without printing it via cout.

m=add(): increment a, copy a int m like x and y.

The output is straightforward once you understand why x,y,m are copies and z is an alias.

Any questions still open?

regards

Tobias

Tobias Langner
  • 10,634
  • 6
  • 46
  • 76