[c++] Why are arrays of references illegal?

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.

This question is related to c++ arrays reference

The answer is


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!


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.


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;
}

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}


An array is implicitly convertable to a pointer, and pointer-to-reference is illegal in 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]); }

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.


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

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.


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.


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.


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.


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."


Examples related to c++

Method Call Chaining; returning a pointer vs a reference? How can I tell if an algorithm is efficient? Difference between opening a file in binary vs text How can compare-and-swap be used for a wait-free mutual exclusion for any shared data structure? Install Qt on Ubuntu #include errors detected in vscode Cannot open include file: 'stdio.h' - Visual Studio Community 2017 - C++ Error How to fix the error "Windows SDK version 8.1" was not found? Visual Studio 2017 errors on standard headers How do I check if a Key is pressed on C++

Examples related to arrays

PHP array value passes to next row Use NSInteger as array index How do I show a message in the foreach loop? Objects are not valid as a React child. If you meant to render a collection of children, use an array instead Iterating over arrays in Python 3 Best way to "push" into C# array Sort Array of object by object field in Angular 6 Checking for duplicate strings in JavaScript array what does numpy ndarray shape do? How to round a numpy array?

Examples related to reference

Method Call Chaining; returning a pointer vs a reference? When to create variables (memory management) Reference to non-static member function must be called Cannot find reference 'xxx' in __init__.py - Python / Pycharm c++ "Incomplete type not allowed" error accessing class reference information (Circular dependency with forward declaration) C++ initial value of reference to non-const must be an lvalue Dependent DLL is not getting copied to the build output folder in Visual Studio How to write to error log file in PHP How to reference Microsoft.Office.Interop.Excel dll? Linker Error C++ "undefined reference "