When Declaring a Reference to an Array of Ints, why must it be a reference to a const-pointer?

20,420

Solution 1

int*& ra = a;

int* is a pointer type, not an array type. So that's why it won't bind to a, which has type int[3].

int* const& ra = a;

works, because it is equivalent to

int* const& ra = (int*)a;

That is, a temporary pointer is conceptually created on the right-hand side of the assignment and this temporary is then bound to ra. So in the end, this is no better than:

int* ra = a;

where ra is in fact a pointer to the first element of the array, not a reference to the array.

Declaring a reference to an array the easy way:

typedef int array_type[3];
array_type& ra = a;

The not-as-easy way:

int (&ra)[3] = a;

The C++11-easy way:

auto& ra = a;

At what point does the name of a statically declared array become a const-pointer? I seem to remember that the name of an array of ints is also a pointer-to-int, but I don't remember it ever being a const-pointer-to-int...

This is the right question to ask! If you understand when array-to-pointer decay happens, then you're safe. Simply put there are two things to consider:

  • decay happens when any kind of 'copying' is attempted (because C doesn't allow arrays to be copied directly)
  • decay is a kind of conversion and can happen anytime a conversion is allowed: when the types don't match

The first kind typically happen with templates. So given template<typename T> pass_by_value(T);, then pass_by_value(a) will actually pass an int*, because the array of type int[3] can't be copied in.

As for the second one, you've already seen it in action: this happens in your second case when int* const& can't bind to int[3], but can bind to a temporary int*, so the conversion happens.

Solution 2

The word "array" in C++ is spelled with brackets []. If you want to declare a something-array-something in C++, you have to have brackets in your declaration. If you write an asterisk * instead, you will get a pointer. Pointers and arrays are two different things.

This is a reference to an array:

int (&ra) [3] = a;

Solution 3

The very big mistake (also a very good interview question) that most people make is that they think the name of an array is equivalent to a pointer. That is NOT true. This mistake causes many bugs in C programs especially linking bugs, and they are very hard to debug. The diffrence is this: The name of the array, is a pointer the first element of a structure, the array. The type of the array name is not a pointertype however, but an arraytype. A pointer, on the other hand, is just a pointer to one thing with no other information. The type of a pointer is a pointertype. An arraytype has some other properties like it knows whether its on the stack or not; therefore, "temporary". The temporary error in your case comes from a check that prevents a temporary variable to be assigned to a reference. The const keyword turns that check off. A pointertype on the other hand has no notion of "temporary". Now suppose you want to trick the compiler and assign a reference to something that is in the stack. In that case, you need to make it a pointer. How?

int*& ra = &a[0];

in the above case you first get the value and using a &(address of operator) you make a pointerType. Now a pointertype has no information about whether its on the stack (a temporary variable) or not. This however, will make a reference to a pointer to the first element of the array. (Therefore just a pointer type, not an arraytype)

Solution 4

If you really want a reference to an array, then you should use the following:

int a[3] = { 4, 5, 6 };
int (&ra)[3] = a;

What you are trying to create with int *& is a reference to a pointer to an int. This is not the same type. And as you initialize the reference with a value that cannot change (the address of the array) you have to declare the pointer const (not the ints).

Solution 5

You have an array of ints :

int a[3] = { 4, 5, 6 };

Now, this line :

int*& ra = a;

creates a reference to a pointer. Since you create a temporary pointer (converted from the array a), the compiler complains, because the standard forbids assignment of temporaries to a reference.

So, to fix it, you need to create a pointer, and then assign it to a reference to a pointer :

int *pa = a;
int *& rpa = pa;

Constant references can hold reference to temporaries, but you already found that out.

What you asked (about reference to an array) - the most famous example about creating a reference to an array is this :

template< typename T, size_t N >
size_t ArraySize( T (&)[ N ] )
{
    return N;
}

This function takes a reference to an array, and returns it's size.

Share:
20,420
Jimmy
Author by

Jimmy

Updated on October 21, 2020

Comments

  • Jimmy
    Jimmy over 3 years

    Note: I am using the g++ compiler (which is I hear is pretty good and supposed to be pretty close to the standard).


    Let's say you have declared an array of ints:

    int a[3] = { 4, 5, 6 };
    

    Now let's say you really want to declare a reference to that array (nevermind why, other than the Bjarne says the language supports it).

    Case 1 -- If you try:

    int*& ra = a;
    

    then the compiler balks and says:

    "invalid initialization of non-const reference of type `int*&' from a temporary of type `int*'"  
    

    First things first, why is 'a' a temporary variable (i.e. doesn't it have a place in memory?)...

    Anyway, fine, whenever I see a non-const error, I try to throw in a const...

    Case 2 -- if you try:

    int*const&rca = a;  //wish I knew where the spaces should go (but my other post asking about this sort of protocol got a negative rank while many of the answers got ranked highly -- aha! there are stupid questions!) 
    

    Then everything is cool, it compiles, and you get a reference to the array.

    Case 3 -- Now here is another thing that will compile:

    int* justSomeIntPointer = a;  //LINE 1
    int*& rpa = justSomeIntPointer;  //LINE 2
    

    This also gives you a reference to the original array.

    So here is my question: At what point does the name of a statically declared array become a const-pointer? I seem to remember that the name of an array of ints is also a pointer-to-int, but I don't remember it ever being a const-pointer-to-int...

    It seems like Case 1 fails because the reference declared (ra) is not to a const-pointer, which may mean that 'a' was already a const-pointer-to-int to begin with.

    It seems like Case 2 works because the reference declared (rca) is already a const-pointer-to-int.

    Case 3 also works, which is neat, but why? At what point does the assumed pointer-to-int (i.e. the array name 'a') become a const-pointer? Does it happen when you assign it to an int* (LINE 1), or does it happen when you assign that int* to a int*& (LINE 2)?

    Hope this makes sense. Thanks.

  • Jimmy
    Jimmy almost 13 years
    So are temporary variables always const?
  • Steve Jessop
    Steve Jessop almost 13 years
    @Jimmy: temporaries are not always const, but the language forbids binding one directly to a non-const reference. The array a isn't a temporary, though, it's the pointer resulting from array-to-pointer conversion that's a temporary.
  • underscore_d
    underscore_d over 8 years
    Declared on the stack means 'has automatic storage duration', i.e. goes out of scope when its containing block/object does - not "temporary". Few consider having to manually manage dynamically allocated objects to be a plus point. The last thing we need is another false idea about why dynamic allocation is better. This one is especially bad because it invokes a false definition of temporary, a term that has a very well-defined, different meaning.