8

I know that reference does not take any memory it will point to the same memory location which it is referencing. for eg

int i=10;
int &r = a;

suppose i points to the memory location 1000 so in this case r will also point to the memory location 1000. But in C++ whenever we are declaring a variable it will get stored in the memory at some location. In this case r is pointing to some location but it should be stored somewhere in memory via some internal representation. thanks in advance.

Hari
  • 1,561
  • 4
  • 17
  • 26
Sandeep Sharma
  • 109
  • 1
  • 10

4 Answers4

11

That is left unspecified, and for good reason. The real answer is: it depends on the reference. It can be represented as a normal pointer, or it may not exist at all.

If you have a function-local reference with automatic storage duration, such as this r:

void foo()
{
  int x[4] = {0, 1, 2, 3};
  int &r = x[1];
  // more code
}

then it will probably not take up any space at all. The compiler will simply treat all uses of r as an alias for x[1], and access that int directly. Notice that such alias-style references can also result from function inlining.

On the other hand, if the reference is "persistent" or visible to other translation units (such as a data member or a global variable), it has to occupy some space and be stored somewhere. In that case, it will most likely be represented as a pointer, and code using it will be compiled to dereference that pointer.

Theoretically, other options would also be possible (such as a lookup table), but I don't think those are used by any real-world compiler.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
5

I know that reference does not take any memory

Not exactly. Whether a reference has storage, is unspecified. It might or it might not. In this particular example, it does not need storage, so in a typical implementation, it doesn't use any.

it's will point to the same memory location which it is referencing

That sounds like a tautology or simply a misunderstanding, depending on what you mean by "point". A reference refers to the object or is bound to the object. You can consider it an alias of the variable name. The variable name doesn't use any memory either.

In this case r is pointing to some location but it should be stored somewhere in memory

It doesn't need to be stored in memory. Consider following code:

int i=10;
int &r = a;
int j = r * 3;

The compiler can interpret r * 3 as i * 3 as if you had written so in the first place. The location of the referred object is known at compile time, so there is no need to store the address in memory which is a run time thing.

But, in other situations, storage may be needed. For example: Consider a reference argument of a non-inline function that has external linkage. The referred object cannot be known when the function is compiled, so some information must be passed along in memory, at run time.

as internal representation on reference use const pointer only

That's not correct. The internal representation might use a pointer, or it might use something else, or it might not need to use anything.

So, to concisely answer

Where does the reference variable gets stored

It is unspecified. Either nowhere, or somewhere.

eerorika
  • 232,697
  • 12
  • 197
  • 326
1

as internal representation on reference use const pointer only

Where did you hear that? That is not true.

The standard doesn't specify how references are implemented.

The following is overly simplified

Most commonly, the compiler has internally a symbol table where it stores all the information it needs about variables.

Let's take a simple case:

int a;
a = 100;

then the compiler can have something like this (for simplicity lets make the address of a a fixed known address)

| identifier | type | address  |
|------------|------|----------|
| a          | int  | 0xFF00A4 |

Then it can translate the c++ code into something like this:

mov 0xFF00A4, 100

Let's add a reference in the mix:

int a;
a = 100;
int& ra = 300;

The symbol table the compiler has:

| identifier | type | address  |
|------------|------|----------|
| a          | int  | 0xFF00A4 |
| ra         | int& | 0xFF00A4 |

Or:

| identifier | type | address  | alias |
|------------|------|----------|-------|
| a          | int  | 0xFF00A4 | -     |
| ra         | int& | -        | a     |

And can therefore generate code like this:

mov 0xFF00A4, 100
mov 0xFF00A4, 300

When you have a reference argument in a function, then a pointer is passed internally.

bolov
  • 72,283
  • 15
  • 145
  • 224
  • This is not specific to references; compilers routinely perform this kind of optimization even on pointers, once everything gets in SSA form there's really no difference. – Matteo Italia Jun 09 '16 at 08:46
0

What the standard says:

It is unspecified whether or not a reference requires storage (3.7).

(C++11, [dcl.ref] ΒΆ4)

This means that the compiler is free to choose on a per-case basis whether or not any storage is required.

Now, let people say what they want, but references boil down to syntactic sugar for pointers (even at compiler level, in all major C++ compilers the "reference" concept disappears almost immediately after the frontend); thus, in the general case they may need their space in memory, exactly like a pointer does. However, in cases like yours (local references) the compiler should see through them and optimize them away as needed.

Notice however that this isn't an exclusive of references - the compiler is able to perform this same kind of optimization even through pointers (once your code goes in SSA form there's nothing special even about the fact that references cannot be reseated).

This:

int glob;

void direct() {
    glob = 16; 
}

void through_reference() {
    int &a = glob;
    a = 16;
}

void through_pointer() {
    int *a = &glob;
    *a = 16;
}

boils down always to the same code on any compiler I tried on gcc.godbolt.org - example:

direct():
        mov     DWORD PTR glob[rip], 16
        ret
through_reference():
        mov     DWORD PTR glob[rip], 16
        ret
through_pointer():
        mov     DWORD PTR glob[rip], 16
        ret
glob:
        .zero   4

On the other hand, the situation gets a bit more slippery when talking about structures; here the compiler is allowed to kill references away from the actual layout of the structure (if it's able to reconstruct what they actually point to), while for pointers the situation may be a bit more complicated (their elision would break the standard-layout classes stuff).

In practice, I never actually saw this kind of optimization implemented in any real-world compiler. Take gcc or MSVC or Clang or whatever and you'll always see that the struct size will come out equal even in the most trivial cases.

Matteo Italia
  • 123,740
  • 17
  • 206
  • 299