4

I read everywhere that references are not objects, they are just aliases and they have no location on the memory

int x = 256;
int& rx = x;

std::cout << x << " " << &x << std::endl;       // Output: 256  0x15FAB0
std::cout << rx << " " << &rx << std::endl;     // Output: 256  0x15FAB0

// seems legit ... fair enough ...

Now consider the following

const int& r1 = 8;      // lvalue ref to const int
int&& r2 = 32;          // rvlaue ref to int
const int&& r3 = 128;   // rvalue ref to const int

std::cout << r1 << " " << &r1 << std::endl;     // Output: 8     0x15FA8C
std::cout << r2 << " " << &r2 << std::endl;     // Output: 32    0x15FA74
std::cout << r3 << " " << &r3 << std::endl;     // Output: 128   0x15FA5C

// and ...

std::cout << sizeof(r1) << std::endl;   // Ouput: 4
std::cout << sizeof(r2) << std::endl;   // Ouput: 4
std::cout << sizeof(r3) << std::endl;   // Ouput: 4

So why these references behave like objects, they do have values , memory address and size ... are they exception from the rules of references ? are they located on the stack or somewhere else ?

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
Laith
  • 1,248
  • 2
  • 11
  • 19
  • 4
    They are aliases for objects, so they behave like the objects they are aliases for. What's the mystery? – user207421 Apr 17 '16 at 12:25
  • "they behave like the objects they are aliases" ... I dont think 8, 32 and 128 are "objects" ... that doesnt make sense – Laith Apr 17 '16 at 12:27
  • They aren't objects but they are values that exist at a memory location and take up a certain size in memory. The reference is assigned to that memory, just as if you set a variable to that memory. It can be an object or a simple value, it doesn't matter. –  Apr 17 '16 at 12:29
  • @WLION They can also be, and behave like, aliases to primitive types.You're the one who said they behave like objects. You can argue with yourself as much as you please but don't drag me into it. – user207421 Apr 17 '16 at 12:32
  • 2
    Chicken-and-egg, you are forcing the compiler to give it an address by using the & address-of operator. If it could avoid it then it would, it can't. – Hans Passant Apr 17 '16 at 12:32
  • 1
    An object is a region of storage (1.8 \[intro.object\]).. 8 is not a region of storage, it is a value that resides in a region of storage. – n. m. could be an AI Apr 17 '16 at 12:39
  • @ EJP I just asked question to clear my doubts Im not arguing ... if you dont like to answer ...just dont please ... thank you – Laith Apr 17 '16 at 12:43
  • 1
    The confusion may arise from the fact that you're thinking of references as tangible things. But they're not. You can generally only access *values* in C++ by evaluating expressions. When you evaluate an expression that consists of the name of a reference variable, the value you obtain is the value that the reference is bound to. You never get to see the reference itself. – Kerrek SB Apr 17 '16 at 12:54

5 Answers5

6

I guess your real question is "where do the rvalue/const references go when they do not reference anything with a name"?

const int& r1 = 8;      // lvalue ref to const int
int&& r2 = 32;          // rvlaue ref to int
const int&& r3 = 128;   // rvalue ref to const int

In all three situations above the compiler allocates space in a temporary location, places the value there, and gives you a reference to that value. The compiler is allowed to do that because it can guarantee that the temporary location would remain read-only.

That is how your references get their addresses - the objects (8, 32, 128) are still there, because the compiler creates them for you. The addresses of these hidden objects become addresses of the references; the sizes of these hidden objects are reported by the sizeof operator.

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • I don't think the temporary on the right hand side of the rvalue reference is read-only. It's simply that the lifetime of a temporary is extended to match the rvalue reference or const lvalue reference that refers to it. – Richard Hodges Apr 17 '16 at 12:53
3

A sizeof() of a reference does not give you the size of the reference itself, but the sizeof() of whatever the reference is referring to.

struct foo {
    int a[128];
};

foo bar;
foo &baz=bar;

std::cout << sizeof(baz) << std::endl;

You'll get a pretty big sizeof() here. Obviously that's not the size of the reference, but the size of the object being referred to.

This applies to both lvalue and rvalue references.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148
2

The reference has an address and a size because it is bound to a temporary. The lifetime of the temporary is therefore being extended to match the lifetime of the reference.

This is expressly covered by §12.2 paras 4,5:

4 There are two contexts in which temporaries are destroyed at a different point than the end of the fullexpression. The first context is when a default constructor is called to initialize an element of an array. If the constructor has one or more default arguments, the destruction of every temporary created in a default argument is sequenced before the construction of the next array element, if any.

5 The second context is when a reference is bound to a temporary.117 The temporary to which the reference is bound or the temporary that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference except: ...

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
1

References are, essentially, another name for the same value. As you can see in your tests they have the same size and address as the original value. If you create a value and reference it directly then the reference will be a name for that value also.

  • But 8, 32 and 128 are rvalues ... so they are not objects neither do they have memory address ... that doesnt seem aliasing to me – Laith Apr 17 '16 at 12:30
  • I'll refer you to this question: http://stackoverflow.com/questions/34221287/how-rvalues-in-c-stored-in-memory –  Apr 17 '16 at 12:32
1
int x = 256;
int& rx = x;

[...]

const int& r1 = 8;      // lvalue ref to const int
int&& r2 = 32;          // rvlaue ref to int
const int&& r3 = 128;   // rvalue ref to const int

There is not much difference between those two examples. In the first example, you declare a reference (rx) to an object which was already named before (x). In the second example, your three references (r1, r2, r3) refer to temporary objects which are created during the initialisation of each reference.

So why these references behave like objects, they do have values , memory address and size ...

They don't. It's just that the objects here are only named by the references and not by anything else. Your sizeof and address-of operators are still applied to those objects.

Christian Hackl
  • 27,051
  • 3
  • 32
  • 62