In func1
, what you are returning is a reference to something. This something is x
, which is local to func1
, whose lifetime ends upon returning. Then, in main
, you assign the contents of the referred-to variable (x
of func1
, which is eating dandelions by the roots) to initialize main
's local variable x
. This is undefined behaviour, which means that the program is allowed to interpret this as anything it wants, formatting your hard drive or anything. (most probably, func1
returned the pointer to the variable of the called stack frame, which probably still contains the right value, because why bother erasing the values on the stack when they will be crushed by the next function call anyway?) Anyway, would the program be compiled with other optimization options, it may give another answer.
In func2
, what you are returning is a reference to something. This something is what is referred-to by x
, which refers to main
's y
. Then, you assign to main
's x
the value of the referred-to variable, which is y
.
With regards to your question of the memory layout of references, in C, pointers are addresses in memory. Period. No escape. In C++, references are a higher-level mechanism where you "refer to something", "talk about something", "look it's me right there". They are perfectly implementable as plain pointers. But as a language concept, they are a bit more amenable to be optimized away, because they are immutable. (Once a reference is set, it cannot be changed. And it refers to something -- even an object at an invalid memory location) That's why the Standard does not specify storage for references. For freedom of optimization.
UPDATE: With regards to your first doubt, main
's x
is a full-fledged variable (it is declared as such) and not a reference. So assigning it any other value will not change y
's value. In C++, when you evaluate a reference in an expression, like so:
int x = 0;
int& y = x;
// Right hand side is the evaluation of the reference y
int z = y;
It gets evaluated to the value of the referred-to variable, i.e. the value of x
, i.e. 0
. And z
is a variable that is distinct from x
.
With regards to your third doubt, func2
will return a reference. When a function is declared as returning a reference, what it returns is a reference. A reference is something that says "I'm this other one over there". In the case of the return value, at assembler level, provided that the function is not inlined and the call really happens, and so on, what will most probably be returned by func1
or func2
will be a pointer to the referred to-variable. Actually, in C++, a reference to an int
is the type of what you get by defererencing an int
pointer with *
. Compare the previous example code with the same code with pointers.
int x = 0;
int* const y = &x;
int z = *y;
With references, the &
and *
occur silently.
Just so you know, references have been introduced into the language to support operator overloading, especially the assignment operator.
// Quizz : what is the type of (b = A(123))? What if it is a 1MB object?
// What should be the type of the right-hand side of the assignment operator?
A a, b;
a = b = A(123);
It can't be a value or it would be performing horrendously bad (passing result by copy). It has to be some kind of pointer, but it can't be. There would be &
s or *
s somewhere, depending on how you word the Standand for the functionality. Instead of inventing lots of special typesystem cases of operator overloading, Stroustrup decided to provide two orthogonal functionality: references, which are syntax-fussless immutable pointers (and the type of "talking about a variable"), and operator overloading which is cleanly enabled by references.