Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deferencing a returned reference

Tags:

c++

reference

Given:

int& foo(); // don't care what the reference is to
int intVal;

In the following two cases the right hand side is the same function call

int& intRef = foo();
intVal = foo();  // a reference is returned... a value is assigned.

In the second case how is the returned reference "converted" into a value?

Is it done by the assignment operator for the int?

like image 848
Arbalest Avatar asked Dec 11 '22 19:12

Arbalest


2 Answers

At the language level there's no such concept as "dereferencing a reference". A reference implements the concept of an lvalue. A variable and a reference are basically the same thing. The only difference between a variable and a reference is that the variable is bound to its location in storage automatically, by the compiler, while a reference is generally bound through user action at run time.

In your example, there's no conceptual difference between intRef and intVal. Both are lvalues of type int. And at the conceptual level both are accessed through the same mechanism. You can even think of all variables in your program as references, which were implicitly pre-bound for you by the compiler. This is basically what Bjarne Stroustrup means in TC++PL when he says (not verbatim) that one can think of references as just alternative names for existing variables.

The only moment when the difference between the two is perceptible is when you create these entities and initialize them. Initialization of a reference is an act of binding it to some location in storage. Initialization of a variable is an act of copying the initial value into the existing storage.

But once a reference is initialized, it acts as an ordinary variable: an act of reading/writing a reference is an act of reading/writing the storage location it is bound to. Taking the address of a reference evaluates to the address of the storage location it is bound to. And so on.

It is not a secret that in many cases a reference is implemented internally as a pointer in disguise, i.e. as an invisible pointer that is implicitly dereferenced for you every time you access it. In such cases (when it is really implemented through a pointer) the dereference is done, again, every time you access it. So, it is not the assignment operator that does it, as you ask in your question. It is the very fact that you mentioned the name of that reference in your code that causes the invisible pointer to get dereferenced.

However, an entity that implements "alternative name for existing variable" does not necessarily require storage for itself, i.e. in a compiled language it is not required to be represented by anything material, like a hidden pointer. This is why the language standard states in 8.3.2 that "It is unspecified whether or not a reference requires storage".

like image 187
AnT Avatar answered Dec 14 '22 09:12

AnT


foo is returning some reference to an object of type "int". We won't care about where that "int" came from and we'll just assume it exists.

The first line, int& intRef = foo(), creates intRef which also refers to exactly the same object of type "int" as is referenced by the return value of foo.

The second line, the value of intVal is replaced by the value of the object referred to by the returned reference.


In response to your comments:

You seem to be getting very confused between pointers and references. References are just like aliases for an object. Doing anything to a reference will actually affect the object it refers to.

There is no such thing as dereferencing a reference. You can only dereference pointers. Dereferencing is the act of using the unary * operator to get the object pointed at by a point. For example, if you have a int* p, you can do *p to get the object that it points at. This is dereferencing p.

The only time you can do * on a reference is if the object it refers to is a pointer (or if it overloads operator*). In your case, since foo returns an int&, we can't dereference it. The expression *foo() just won't compile. That's because the return value of foo has type "int" which is not a pointer and doesn't overload operator*.

For all intents and purposes, you can treat the reference returned from foo as simply being the object it refers to. Assigning this value to intVal is really no different to assigning x to intVal in the following code:

int intVal;
int x = 5;
intVal = x;

As I'm sure you understand, intVal is given the value of x. This is defined simply by the standard:

In simple assignment (=), the value of the expression replaces that of the object referred to by the left operand.

No conversion needs to occur at all because both sides of the operator are the same type.

This is really no different to your situation. You just have:

intVal = some_ref_to_int;

Where some_ref_to_int is the expression foo(). The fact that it's a reference doesn't matter. intVal receives the value of the object that the reference denotes.

like image 37
Joseph Mansfield Avatar answered Dec 14 '22 08:12

Joseph Mansfield