A reference provides another name for a variable. Whatever you do to a reference is done to the variable to which it refers. You can think of a reference as a nickname for a variable.
anything done to r is done to the variable x
anything done to x is done to r
they're both the same thing, just different names.
int x = 7 ; // x is an object of type int
// x has an address (of type pointer to int)
// an object is a region of storage that has a size, a type, and a lifetime
// this object was created by the definition of the variable x of type int
int& r = x ; // r is a variable, but it is not an object
// the variable r refers to (is an alias for) the the object x.
// r has no address of its own; and it may not occupy any storage at all
// r is an alias for x, and &r yields the address of x
// (references are not objects; we can't have arrays of references)
// (references are not objects; we can't use new to allocate a reference)
int* p = &x ; // p is an object of type pointer to int (initialised with the address of x)
// p is an object; it has an address (of type pointer to pointer to int)
// p is a region of storage that has a size, a type, and a lifetime
// this object was created by the definition of the variable of type pointer to int
When you see the ampersand being used with the data type immediately to the left and the variable name immediately to the right, such as in the creation of a reference or in declaring functions argument list, then it is being used as the reference operator. If you see this character immediately to the left of an already existing variable then it is being used as an address of operator. This is my attempt at creating a "rule of thumb" for this and I'm confident that it's accurate. I'm sure I will be corrected if it is not.
With int myfun();, the expression myfun() yields a prvalue (a pure rvalue).
A prvalue either identifies a temporary object or, as in this example, a value that is not associated with any object.
With int& myfun();, the expression myfun() yields an lvalue.
That lvalue identifies a non-temporary object of type int.
1 2 3 4 5 6 7 8 9 10 11 12 13
int fn1() { return 67 ; } // fine
int fn2() { int i = 6 ; return i ; } // fine.
// the lifetime of the local objct i is over once the function returns.
// but we are not returning the object i; we are returning a prvalue initialised with i
int& fn3() { return 67 ; } // *** error: 67 is not an lvalue
int& fn4() { int i = 6 ; return i ; } // *** logical error: we are returning an lvalue
// but the lifetime of the local objct i is over once the function returns.
int& fn5() { staticint i = 6 ; return i ; } // fine: lifetime of i extends beyond the return
fn1() = 23 ; // *** error: can't assign to rvalue
fn5() = 23 ; // fine: assign to lvalue ( assign to static int i in fn5() )