Amit
Amit

Reputation: 84

Do references take memory in C++?

I have read many articles on this question, from which I get that references are only aliases and they don't consume any memory. Compiler replace the reference with the address of pointing variable.

Can any one explain what will happen for below example. How compiler work with reference ri?

int main()
{  
    int *pi = new int(50);
    int &ri = *pi;
    ri = 30;
    cout << "val = " << ri << " , " << *pi << endl;
}

It gives me the output:

val = 30  ,   30

Upvotes: 4

Views: 2389

Answers (6)

techboost.in
techboost.in

Reputation: 9

Reference variable takes memory on the stack , Best way to test this is using assembly of a c++ program as shown below.... write a c++ program as shown below and generate a assembly of it

#include<iostream>
using namespace std;

int main(){
int i = 100;
int j = 200;
int &x1 = i;
int &x2 = i;
int &x3 = i;
int &x4 = i;
int &x5 = i;
int &x6 = i;
int &x7 = i;

cout << "reference value" << x1 << endl;
return 0;

}

Assembly of this program shows that stack pointer moved down upto 36 byte "which means reference gets memory".

main:
.LFB966:
.cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    pushl   %ebx
    andl    $-16, %esp
    subl    $64, %esp   
    movl    $100, 28(%esp)

Above instruction ( subl $64, %esp )is stack pointer movement to allocate space for i , j and seven reference variables(x1 to x7) on the stack.

If you change above cpp program as below

#include<iostream>
using namespace std;

int main(){
int i = 100;
int j = 200;
int &x1 = i;
cout << "ref changed" << x1 << endl; 
return 0;
}

Assembly of it showing stack pointer movement of 12 bytes..

main:
.LFB966:
   .cfi_startproc
    pushl   %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl    %esp, %ebp
    .cfi_def_cfa_register 5
    pushl   %ebx
    andl    $-16, %esp
    subl    $32, %esp 
    movl    $100, 20(%esp)

Above instruction "subl $32, %esp " is stack pointer movement to allocate space for i, j and x1 reference variable on the stack

I believe above practical clears every thing, Correct me if I am wrong .. :)

Upvotes: 0

Matthieu M.
Matthieu M.

Reputation: 300029

References are defined as aliases. The Standard does not specify how they are represented, though the implementations do not vary much. Essentially:

  • In the general case, the reference is, under the hood, the address of the object (like a pointer)
  • Whenever possible, the compiler will strive to eliminate the indirection

Let us see how it translates, starting with your program:

int main()
{  
    int *pi = new int(50);
    int &ri = *pi;
    ri = 30;
    std::cout << "val = " << ri << " , " << *pi << std::endl;
}

We can eliminate ri, because the object it is bound to is known by the compiler:

int main()
{  
    int *pi = new int(50);
    *pi = 30;
    std::cout << "val = " << *pi << " , " << *pi << std::endl;
}

We can eliminate *pi because its final value is known by the compiler:

int main() {
  new int(50); // stupid possible side effect usually forbid to optimize this out
  std::cout << "val = " << 30 << " , " << 30 << std::endl;
}

I would note that in your example, the new call is completely useless, you can also reference objects that have not been dynamically allocated.

int main() {
  int i = 50;
  int& ri = i;
  ri = 30;
  std::cout << "val = " << ri << " < " << i << std::endl;
}

was equally valid, and without memory leak.


Getting back to our distinction between the representations:

void swap(Foo& left, Foo& right);

is typically implemented as:

void swap(Foo* left, Foo* right);

In this case, the reference ends up taking (some) space (as much as a pointer).

On the other hand with:

class Object {
public:
  Object(): foo(f), f() {}

  Foo const& foo;

  void set(Foo const& value);

private:
  Foo f;
};

Compiler will typically not give foo a runtime representation. The fact that it is a const reference will be used to restrict the possible methods invoked on f to those not changing it (semantic difference) but at runtime they will directly be passed f.

Upvotes: 2

benlong
benlong

Reputation: 678

int *pi = new int(50);

you allocate an int object 50;

int &ri = *pi;

you set a alias ri to this int object, ri is this object and pi is the address of the object;

ri = 30;

reassign 30 to the int object; remember ri is the int object;

cout << "val = " << ri << " , " << *pi << endl;

ri and *pi are the same object. You just remember an object could have many aliases , and using anyone of these aliases can manipulate the object.

and where is the delete.

Upvotes: 1

rerun
rerun

Reputation: 25505

ri is a stack variable that works just like a pointer that you can't assign to a new memory address. It is mostly a semantic sugar there is nothing you can do with a reference you can't do with a pointer you can just do it more safely. When this function terminate the space utilized by ri will be cleaned up off the stack.

Upvotes: 0

AndersK
AndersK

Reputation: 36102

int *pi = new int(50);

       +----+
pi --> | 50 |
       +----+


int &ri = *pi;

        +----+
pi  --> | 50 |    ri = 50, same as *pi, which is 50
        +----+

ri = 30;      now the contents of what pi points to i.e. *pi is replaced with 30

        +----+
pi  --> | 30 |
        +----+

Upvotes: 2

Sarfaraz Nawaz
Sarfaraz Nawaz

Reputation: 361612

The compiler might replace the reference with the actual object as:

int main()
{  
    int *pi = new int(50);
    //int &ri = *pi; //compiler might remove this

    *pi = 30; //then it replaces ri with *pi 

    cout << "val = " << *pi << " , " << *pi << endl; //here as well
}

This is one thing that compiler might do.

Upvotes: 1

Related Questions