Why are arrays of references illegal?

C++ArraysReference

C++ Problem Overview


The following code does not compile.

int a = 1, b = 2, c = 3;
int& arr[] = {a,b,c,8};

What does the C++ standard say about this?

I know I could declare a class that contains a reference, then create an array of that class, as shown below. But I really want to know why the code above doesn't compile.

struct cintref
{
    cintref(const int & ref) : ref(ref) {}
    operator const int &() { return ref; }
private:
    const int & ref;
    void operator=(const cintref &);
};

int main() 
{
  int a=1,b=2,c=3;
  //typedef const int &  cintref;
  cintref arr[] = {a,b,c,8};
}

It is possible to use struct cintref instead of const int & to simulate an array of references.

C++ Solutions


Solution 1 - C++

Answering to your question about standard I can cite the C++ Standard §8.3.2/4: > There shall be no references to references, no arrays of references, and no pointers to references.

That's because references are not objects and doesn't occupy the memory so doesn't have the address. You can think of them as the aliases to the objects. Declaring an array of nothing has not much sense.

Solution 2 - C++

References are not objects. They don't have storage of their own, they just reference existing objects. For this reason it doesn't make sense to have arrays of references.

If you want a light-weight object that references another object then you can use a pointer. You will only be able to use a struct with a reference member as objects in arrays if you provide explicit initialization for all the reference members for all struct instances. References cannot be default initalized.

Edit: As jia3ep notes, in the standard section on declarations there is an explicit prohibition on arrays of references.

Solution 3 - C++

This is an interesting discussion. Clearly arrays of refs are outright illegal, but IMHO the reason why is not so simple as saying 'they are not objects' or 'they have no size'. I'd point out that arrays themselves are not full-fledged objects in C/C++ - if you object to that, try instantiating some stl template classes using an array as a 'class' template parameter, and see what happens. You can't return them, assign them, pass them as parameters. ( an array param is treated as a pointer). But it is legal to make arrays of arrays. References do have a size that the compiler can and must calculate - you can't sizeof() a reference, but you can make a struct containing nothing but references. It will have a size sufficient to contain all the pointers which implement the references. You can't instantiate such a struct without initializing all the members:

struct mys {
 int & a;
 int & b;
 int & c;
};
...
int ivar1, ivar2, arr[200];
mys my_refs = { ivar1, ivar2, arr[12] };

my_refs.a += 3  ;  // add 3 to ivar1

In fact you can add this line to the struct definition

struct mys {
 ...
 int & operator[]( int i ) { return i==0?a : i==1? b : c; }
};

...and now I have something which looks a LOT like an array of refs:

int ivar1, ivar2, arr[200];
mys my_refs = { ivar1, ivar2, arr[12] };

my_refs[1] = my_refs[2]  ;  // copy arr[12] to ivar2
&my_refs[0];               // gives &my_refs.a == &ivar1

Now, this is not a real array, it's an operator overload; it won't do things that arrays normally do like sizeof(arr)/sizeof(arr[0]), for instance. But it does exactly what I want an array of references to do, with perfectly legal C++. Except (a) it's a pain to set up for more than 3 or 4 elements, and (b) it's doing a calculation using a bunch of ?: which could be done using indexing (not with normal C-pointer-calculation-semantics indexing, but indexing nonetheless). I'd like to see a very limited 'array of reference' type which can actually do this. I.e. an array of references would not be treated as a general array of things which are references, but rather it would be a new 'array-of-reference' thing which effectively maps to an internally generated class similar to the one above (but which you unfortunately can't make with templates).

this would probably work, if you don't mind this kind of nasty: recast '*this' as an array of int *'s and return a reference made from one: (not recommended, but it shows how the proper 'array' would work):

 int & operator[]( int i ) { return *(reinterpret_cast<int**>(this)[i]); }

 

Solution 4 - C++

Comment to your edit:

Better solution is std::reference_wrapper.

Details: http://www.cplusplus.com/reference/functional/reference_wrapper/

Example:

#include <iostream>
#include <functional>
using namespace std;

int main() {
	int a=1,b=2,c=3,d=4;
    using intlink = std::reference_wrapper<int>;
    intlink arr[] = {a,b,c,d};
	return 0;
}

Solution 5 - C++

An array is implicitly convertable to a pointer, and pointer-to-reference is illegal in C++

Solution 6 - C++

Given int& arr[] = {a,b,c,8};, what is sizeof(*arr) ?

Everywhere else, a reference is treated as being simply the thing itself, so sizeof(*arr) should simply be sizeof(int). But this would make array pointer arithmetic on this array wrong (assuming that references are not the same widths is ints). To eliminate the ambiguity, it's forbidden.

Solution 7 - C++

Because like many have said here, references are not objects. they are simply aliases. True some compilers might implement them as pointers, but the standard does not force/specify that. And because references are not objects, you cannot point to them. Storing elements in an array means there is some kind of index address (i.e., pointing to elements at a certain index); and that is why you cannot have arrays of references, because you cannot point to them.

Use boost::reference_wrapper, or boost::tuple instead; or just pointers.

Solution 8 - C++

I believe the answer is very simple and it has to do with semantic rules of references and how arrays are handled in C++.

In short: References can be thought of as structs which don't have a default constructor, so all the same rules apply.

  1. Semantically, references don't have a default value. References can only be created by referencing something. References don't have a value to represent the absence of a reference.

  2. When allocating an array of size X, program creates a collection of default-initialized objects. Since reference doesn't have a default value, creating such an array is semantically illegal.

This rule also applies to structs/classes which don't have a default constructor. The following code sample doesn't compile:

struct Object
{
	Object(int value) { }
};

Object objects[1]; // Error: no appropriate default constructor available

Solution 9 - C++

You can get fairly close with this template struct. However, you need to initialize with expressions that are pointers to T, rather than T; and so, though you can easily make a 'fake_constref_array' similarly, you won't be able to bind that to rvalues as done in the OP's example ('8');

#include <stdio.h>

template<class T, int N> 
struct fake_ref_array {
   T * ptrs[N];
  T & operator [] ( int i ){ return *ptrs[i]; }
};

int A,B,X[3];

void func( int j, int k)
{
  fake_ref_array<int,3> refarr = { &A, &B, &X[1] };
  refarr[j] = k;  // :-) 
   // You could probably make the following work using an overload of + that returns
   // a proxy that overloads *. Still not a real array though, so it would just be
   // stunt programming at that point.
   // *(refarr + j) = k  
}

int
main()
{
	func(1,7);	//B = 7
	func(2,8);     // X[1] = 8
	printf("A=%d B=%d X = {%d,%d,%d}\n", A,B,X[0],X[1],X[2]);
        return 0;
}

--> A=0 B=7 X = {0,8,0}

Solution 10 - C++

Just to add to all the conversation. Since arrays requires consecutive memory locations to store the item, so if we create an array of references then it's not guaranteed that they will be at consecutive memory location so accessing will be a problem and hence we can't even apply all the mathematical operations on array.

Solution 11 - C++

A reference object has no size. If you write sizeof(referenceVariable), it will give you the size of the object referenced by referenceVariable, not that of the reference itself. It has no size of its own, which is why the compiler can't calculate how much size the array would require.

Solution 12 - C++

When you store something in an array , its size needs to be known (since array indexing relies on the size). Per the C++ standard It is unspecified whether or not a reference requires storage, as a result indexing an array of references would not be possible.

Solution 13 - C++

Consider an array of pointers. A pointer is really an address; so when you initialize the array, you are analogously telling the computer, "allocate this block of memory to hold these X numbers (which are addresses of other items)." Then if you change one of the pointers, you are just changing what it points to; it is still a numerical address which is itself sitting in the same spot.

A reference is analogous to an alias. If you were to declare an array of references, you would basically be telling the computer, "allocate this amorphous blob of memory consisting of all these different items scattered around."

Solution 14 - C++

Actually, this is a mixture of C and C++ syntax.

You should either use pure C arrays, which cannot be of references, since reference are part of C++ only. Or you go the C++ way and use the std::vector or std::array class for your purpose.

As for the edited part: Even though the struct is an element from C, you define a constructor and operator functions, which make it a C++ class. Consequently, your struct would not compile in pure C!

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionAlexey MalistovView Question on Stackoverflow
Solution 1 - C++Kirill V. LyadvinskyView Answer on Stackoverflow
Solution 2 - C++CB BaileyView Answer on Stackoverflow
Solution 3 - C++greggoView Answer on Stackoverflow
Solution 4 - C++YouwView Answer on Stackoverflow
Solution 5 - C++EFraimView Answer on Stackoverflow
Solution 6 - C++PaulMurrayCbrView Answer on Stackoverflow
Solution 7 - C++navigatorView Answer on Stackoverflow
Solution 8 - C++Kristupas A.View Answer on Stackoverflow
Solution 9 - C++greggoView Answer on Stackoverflow
Solution 10 - C++Amit KumarView Answer on Stackoverflow
Solution 11 - C++Carl SeleborgView Answer on Stackoverflow
Solution 12 - C++PradyotView Answer on Stackoverflow
Solution 13 - C++Dan TaoView Answer on Stackoverflow
Solution 14 - C++ThargonView Answer on Stackoverflow