When Declaring a Reference to an Array of Ints, why must it be a reference to a const-pointer?
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.
Jimmy
Updated on October 21, 2020Comments
-
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 almost 13 yearsSo are temporary variables always const?
-
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 over 8 yearsDeclared 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.