Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 402
Jimmy Avatar asked Jul 26 '11 08:07

Jimmy


People also ask

Why is an array called as a constant pointer?

An array name contains the address of first element of the array which acts like constant pointer. It means, the address stored in array name can't be changed.

Why can't you declare an array of references a pointer to a reference?

An array of references is illegal because a reference is not an object. According to the C++ standard, an object is a region of storage, and it is not specified if a reference needs storage (Standard §11.3.

When should I use references and when should I use pointers?

Use references when you can, and pointers when you have to. References are usually preferred over pointers whenever you don't need “reseating”. This usually means that references are most useful in a class's public interface. References typically appear on the skin of an object, and pointers on the inside.


2 Answers

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.

like image 56
Luc Danton Avatar answered Oct 13 '22 23:10

Luc Danton


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;
like image 28
n. 1.8e9-where's-my-share m. Avatar answered Oct 14 '22 01:10

n. 1.8e9-where's-my-share m.