Use of & operator in C++ function parameters: pass-by-rvalue-reference

1.6k Views Asked by At

I am bit surprised with this code snippet! the caller is passing value, but how is the function handling its address ?

void increase1(int &value) {
   value++;
}

int main() {
   int number = 5;
   increase1(number);
}

It would be helpful if someone explains in detail. Thank you.

3

There are 3 best solutions below

2
On

Because increase1 takes a reference to an int, the caller sends the value by reference automatically.

Sending a value by reference functions the same as sending a pointer, except that

  • You don't have to take the address; it knows to do it automatically
  • You can use a reference just like it were a regular variable
  • References are assumed not to be null. This is useful, because it means that you don't have to do null checks inside a function that takes a reference.

If the reference is coming from a pointer, check to make sure the pointer isn't null before converting it into a reference. If you already know the pointer isn't null, then you don't have to check (of course).

2
On

'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)

  1. 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.
  2. 5 is an R-value. The compiler creates a move instruction to move 5 into the memory location for number.
  3. 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.
  4. 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.

0
On

It's a reference.

`int a;   //variable
int @a;  //reference
int *a;  //pointer`

Reference is like a pointer that you must initialize first and can not change. But you can change the value on that address. And after declaration you don't need to put a * before it.

Right declaration example: int &a=b; now to use it, you just write a. And when you change a, the same change will occur to b