'increase1(int& value)` takes an 'l-value reference'. Prior to C++11, we only learned about "references". All references were to l-values.
What is an l-value? A simplified definition of an l-value is something that the compiler can provide an address to. So, a variable, such as value
, has a physical storage location (assuming its memory location has not be optimized away).
A scalar such as 5 or even the sum of two variables, e.g. x + y
do not have memory locations. The compiler does not store 5 in memory. Rather, it moves a 5
into the storage location for number
. The compiler does not store x + y
as a memory location. Again, on a simplified basis, 5
is a concept and (x + y) is a concept -- these are r-values. References to R-Values are the second type of reference [not discussed here].
Coming back to your excellent example, int &value
describes an l-value reference because value
refers to a location in memory.
The main() function (assuming no optimization)
- declares
number
as an int and allocates, storage for number. On most 32 bit and 64 bit systems, 4 bytes of memory are allocated for number.
- 5 is an R-value. The compiler creates a move instruction to move
5
into the memory location for number.
main()
now calls increase1()
by passing the storage location of number. The variable is passed by reference, which means the address is passed to increase1
. main()
knows to pass the address because `increase1() takes an l-value reference.
increase1()
receives the address of number and dereferences it to get the 5 value, adds one to the dereferenced pointer, and then stores the result back into the location addressed as number
.
L-value references allow the callee function to directly modify the storage that is owned by the caller.
Note that the storage addresses are passed around. The addresses could be from main()'s stack, or from the heap (allocated by new). In the example, main() allocates number
from the stack, but it need not be from the stack.
A very long-winded way of saying that an l-value reference will be passed using addresses, unless the compiler recognizes that it can do it faster through an optimization. If the compiler optimizes the actual passage of references though, the logical understanding will still be valid.