0

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.

Vin
  • 51
  • 5
  • look up "reference" – Kenny Ostrom Mar 27 '19 at 03:28
  • 2
    When `&` appears in a function parameter like that (or in any type name), it's a modifier, not an operator. – Ben Voigt Mar 27 '19 at 04:32
  • @BenVoigt So if we declare variable as `int &i`. What does this exactly mean. – Vin Mar 27 '19 at 05:14
  • You could only do an uninitialized reference declaration as a member variable inside a struct or class. A local or global variable which is a reference has to be immediately bound. For example, you could have a loop `for( int i = 0; i < v.size(); ++i ) { int &r = v[i]; /* read and write using r */ }` – Ben Voigt Mar 27 '19 at 05:17
  • there are tons of duplicates: [Use of the & operator in C++ function signatures](https://stackoverflow.com/q/6877052/995714), [What does & in C++ function arguments list mean?](https://stackoverflow.com/q/12971310/995714), [What does a function prototype mean with an ampersand in it?](https://stackoverflow.com/q/9488894/995714) – phuclv Mar 27 '19 at 14:59

3 Answers3

2

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

Gardener
  • 2,591
  • 1
  • 13
  • 22
  • Thank you for the detailed answer. It clearly explains what happens in the background. So, to put this in simple words, we are passing the address to the function (Which is done automatically). – Vin Mar 27 '19 at 05:08
  • Yes. I find it helpful to always use the term 'L-value reference' when talking about `int& variable`, because there are two other types of references to learn. – Gardener Mar 27 '19 at 12:04
0

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

Alecto Irene Perez
  • 10,321
  • 23
  • 46
  • So the reference is automatically handled, and we can use the reference just like a variable. Understood, Thank you. @Jorge Perez – Vin Mar 27 '19 at 03:52
  • Yeah! That's what makes references great :) Also, there's no way to re-assign a reference, so you can't accidentally change what it references. – Alecto Irene Perez Mar 27 '19 at 04:00
0

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