4

The book said: Because references are not objects, we may not define a reference to a reference.

int ival = 1024;
int &refVal = ival;
refVal = 2;
int ii = refVal;
int &refVal3 = refVal; // isn't this a definition of ref to ref?
int i = refVal;
int &refVal4 = 10;
double dval = 3.14;
int &refVal5 = dval;

However, that line is not an error, because refVal3 is saying it is just another alias for refVal, and refVal is just another name for ival(refVal3 is bound to the object to which refVal is bound to, which is ival)... so both refVal and refVal3 refer to the initializer of ival.

That makes perfect sense, but if that's not a definition of a reference to a reference, just what exactly does the book mean when it mentioned "Because references are not objects, we may not define a reference to a reference." ??

Can someone perhaps give me an example ?

FormosaTBM
  • 41
  • 1
  • `int &refVal3 = &refVal;` (or `int &&refVal3 = &refVal;`?) would be a reference to a reference; what you actually have is just an assignment of one reference to another. – Ken Y-N Jul 25 '17 at 03:45
  • but isn't int &refVal3 = refVal; a definition? considering it has a type in front. wouldn't an assignment simply be assigning a value to an already defined variable? like line 3 – FormosaTBM Jul 25 '17 at 03:49
  • @KenY-N `&refVal` will return a pointer (i.e. `int*`). – songyuanyao Jul 25 '17 at 03:52
  • It's both, I suppose - I've been slack with my terminology, so it's declaring a reference, and initialising it to another reference. If you replaced the `&` with `*` and thought about this problem as pointer-based, it would perhaps be clearer that we just declare a reference/pointer and initialise it to reference/point to the same thing as another reference/pointer. – Ken Y-N Jul 25 '17 at 03:54
  • 1
    The book sentence is badly worded. An expression cannot have reference type, and the initializer for a reference is an expression. Therefore it is impossible to even express in syntax the concept of forming a reference to a reference. – M.M Jul 25 '17 at 04:17

2 Answers2

5

Your understanding is correct.

int &refVal3 = refVal;

This makes refVal3 a reference to the same thing refVal is a reference to. That is, ival.

just what exactly does the book mean when it mentioned "Because references are not objects, we may not define a reference to a reference." ?

A reference can only refer to an object. But references are not objects. So a reference cannot refer to a reference. And when the book says this, it doesn't just mean that it's not allowed, and you'll get an error if you try. But you can't even try. There's no syntax for it. Because anything you try to do to a reference, you will actually be doing to the object it refers to, and not to the reference itself.

Can someone perhaps give me an example ?

No. I can't. And that's the point. There's simply no syntax for it.

Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
1

Reference-to-reference types (like T & &) do not exist in C++.

Where T is an object type (which includes int, as in your example):

(Similarly, cv-qualified types like const T& exist, while types like const T & & do not exist.)

You asked for an example. Consider this wrong code:

int main()
{
    int ival = 1024;
    int &refVal = ival;
    int & &refRefVal = refVal;   // wrong
}

This is an error because there is no such type as int & &. It would be an error regardless of what I tried to initialize it with.

(Strictly speaking, it is an error because the syntax of the language prohibits it. The standards committee could have chosen to allow me to write int & & and have it mean the same thing as int &--see Reference Collapsing below--but they didn't, which is good, because that would be very confusing.)

When I attempt to compile that wrong code with Clang 3.8, I get:

error: 'refRefVal' declared as a reference to a reference

Other compilers give similar errors. For example, Microsoft Visual C++ gives:

error C2529: 'refRefVal': reference to reference is illegal

When you use a reference, the effect is to use the object it refers to.

References are dereferenced automatically in most contexts where they appear. Anything you try to do to a reference, really you are doing it to the object it refers to. Unlike pointers, there is no operator for dereferencing a reference; in effect the reference is a name for the referenced object.

What you have written (int &refVal3 = refVal;) is not an error, because you are simply initializing a second reference bound to the same object. To see why this is, consider the effect of several of your statements.

Here you create an int, initializing it with the value 1024:

int ival = 1024;

Here you make an lvalue reference, bound to that int object:

int &refVal = ival;

Here you assign 2 to the original int object, because refVal is used as the object to which it refers:

refVal = 2;

Here you create a second int object, initialized with the value of the original object, also because refVal is used as the object to which it refers:

int ii = refVal;

Here you make a second lvalue reference to the original object, also because refVal is used as the object to which it refers:

int &refVal3 = refVal;

Code that looks like it creates a second reference to the first one is, therefore, really creating a second reference to the original object.

This is to say that the reason int &refVal3 = refVal; introduces another reference to the original object--rather than attempting to create a reference to a reference--is that this is just another consequence of refVal being automatically taken to mean the int it refers to.

Reference Collapsing

You can't write types named like T & & yourself, but what about this?

using Ref = int&;
using RefRef = Ref&; // I named this poorly, it's not really a reference to a reference!

This causes the compiler to see that I am trying to make a type alias RefRef to be int& &. The compiler follows the rules of reference collapsing. It collapses the two references into one, so the effect is the same as if I had written:

using RefRef = int&;

This behavior is useful in situations that involve type deduction, such as with templates, both by allowing more code to compile and work as expected than otherwise would, and by facilitating perfect forwarding. (One might argue it also parallels what you observed--when you initialize references from references, you can still never get a reference to a reference, only to an object.)

In no case is there ever anything whose type is reference to reference. The C++ language simply does not have any such types.

Community
  • 1
  • 1
Eliah Kagan
  • 1,704
  • 3
  • 22
  • 38