Почему массивы ссылок являются незаконными?

Следующий код не компилируется.

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

Что говорит об этом стандарт С++?

Я знаю, что могу объявить класс, содержащий ссылку, а затем создать массив этого класса, как показано ниже. Но я действительно хочу знать, почему код выше не компилируется.

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

Для моделирования массива ссылок можно использовать struct cintref вместо const int &.

Ответ 1

Отвечая на ваш вопрос о стандарте, я могу привести С++ Standard & sect; 8.3.2/4:

Не должно быть ссылок на ссылки, нет массивов ссылок и ссылок на ссылки нет.

Ответ 2

Ссылки не являются объектами. У них нет собственного хранилища, они просто ссылаются на существующие объекты. По этой причине нет смысла иметь массивы ссылок.

Если вам нужен легкий объект, который ссылается на другой объект, вы можете использовать указатель. Вы сможете использовать struct с ссылочным элементом как объекты в массивах, если вы предоставляете явную инициализацию для всех ссылочных элементов для всех экземпляров struct. Ссылки не могут быть инициализированы по умолчанию.

Изменить: Как отмечает jia3ep, в стандартном разделе объявлений есть явный запрет на массивы ссылок.

Ответ 3

Это интересная дискуссия. Ясно, что массивы ссылок абсолютно незаконны, но ИМХО причина, почему это не так просто, как сказать "они не объекты" или "они не имеют размера". Я бы указал, что сами массивы не являются полнофункциональными объектами в C/С++ - если вы возражаете против этого, попробуйте создать экземпляр некоторых классов шаблонов stl с использованием массива в качестве параметра шаблона класса и посмотреть, что произойдет. Вы не можете вернуть их, назначить им, передать их в качестве параметров. (параметр массива рассматривается как указатель). Но законно создавать массивы массивов. Ссылки имеют размер, который компилятор может и должен вычислять - вы не можете sizeof() ссылку, но вы можете сделать структуру, содержащую ничего, кроме ссылок. Он будет иметь размер, достаточный для того, чтобы содержать все указатели, которые реализуют ссылки. Вы не можете создать такую ​​структуру без инициализации всех членов:

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

Фактически вы можете добавить эту строку в определение структуры

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

... и теперь у меня есть что-то, что выглядит LOT, как массив ссылок:

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

Теперь это не настоящий массив, это перегрузка оператора; он не будет делать то, что массивы обычно делают, например, sizeof (arr)/sizeof (arr [0]). Но он делает именно то, что я хочу, чтобы иметь множество ссылок, с совершенно законным С++. За исключением того, что (a) боль в настройке для более чем 3 или 4 элементов и (b) он выполняет расчет с использованием пула?: Это можно сделать с помощью индексации (не с обычным индексом индексирования C-указателя-семантики, но тем не менее индексирование). Я бы хотел увидеть очень ограниченный тип "массив ссылок", который действительно может это сделать. То есть массив ссылок не будет рассматриваться как общий массив вещей, которые являются ссылками, но скорее это будет новая "массив ссылок", которая эффективно сопоставляется с внутренне сгенерированным классом, аналогичным тому, что было выше (но которое вы к сожалению, нельзя создавать шаблоны).

это, вероятно, сработает, если вы не возражаете против такого рода противников: recast '* this' как массив int * и верните ссылку, сделанную из одного: (не рекомендуется, но показывает, как правильный массив 'будет работать):

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

Ответ 4

Комментарий к редактированию:

Лучшее решение - std::reference_wrapper.

Подробнее: http://www.cplusplus.com/reference/functional/reference_wrapper/

Пример:

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

Ответ 6

Учитывая int& arr[] = {a,b,c,8};, что такое sizeof(*arr)?

В любом случае ссылка рассматривается как просто сама вещь, поэтому sizeof(*arr) должна быть просто sizeof(int). Но это сделало бы неправильной арифметику указателя на этом массиве (предполагая, что ссылки не являются одинаковыми ширинами, это ints). Чтобы устранить двусмысленность, это запрещено.

Ответ 7

Потому что, как многие говорили здесь, ссылки не являются объектами. это просто псевдонимы. Правда, некоторые компиляторы могут реализовать их как указатели, но стандарт не форсирует/не определяет это. И поскольку ссылки не являются объектами, вы не можете указать на них. Хранение элементов в массиве означает, что есть какой-то индексный адрес (т.е. Указывая на элементы с определенным индексом); и поэтому вы не можете иметь массивы ссылок, потому что вы не можете указать на них.

Используйте boost:: reference_wrapper или boost:: tuple; или просто указатели.

Ответ 8

Вы можете получить довольно близко к этой структуре шаблона. Однако вам нужно инициализировать выражения, которые являются указателями на T, а не T; и поэтому, хотя вы можете легко создать "fake_constref_array" аналогично, вы не сможете связать это с rvalues, как это сделано в примере OP ( "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}

Ответ 9

Объект ссылки не имеет размера. Если вы напишете sizeof(referenceVariable), это даст вам размер объекта, на который ссылается referenceVariable, а не на ссылку. Он не имеет собственного размера, поэтому компилятор не может вычислить, сколько потребуется размер массива.

Ответ 10

Когда вы храните что-то в массиве, его размер должен быть известен (поскольку индексирование массива зависит от размера). По стандарту С++ Не указано, требуется ли эта ссылка для хранения, в результате индексация массива ссылок невозможна.

Ответ 11

Просто чтобы добавить ко всем разговорам. Так как массивы требуют последовательных мест памяти для хранения элемента, поэтому, если мы создадим массив ссылок, то это не гарантирует, что они будут находиться в последовательной ячейке памяти, поэтому доступ к ней будет проблемой, и поэтому мы не можем даже применять все математические операции на массив.

Ответ 12

Рассмотрим массив указателей. Указатель действительно является адресом; поэтому, когда вы инициализируете массив, вы аналогично говорите компьютеру, "выделите этот блок памяти для хранения этих X-номеров (которые являются адресами других элементов)". Затем, если вы измените один из указателей, вы просто изменяете то, на что оно указывает; он по-прежнему является числовым адресом, который сам сидит в одном месте.

Ссылка аналогична псевдониму. Если бы вы объявили массив ссылок, вы в основном сообщали бы компьютеру, "выделите этот аморфный блок памяти, состоящий из всех этих разных элементов, рассеянных вокруг".

Ответ 13

Я считаю, что ответ очень прост, и он имеет отношение к семантическим правилам ссылок и тому, как массивы обрабатываются в C++.

Короче: ссылки можно рассматривать как структуры, не имеющие конструктора по умолчанию, поэтому применяются все те же правила.

1) Семантически ссылки не имеют значения по умолчанию. Ссылки могут быть созданы только путем ссылки на что-то. Ссылки не имеют значения для представления отсутствия ссылки.

2) При распределении массива размера X программа создает коллекцию инициализированных по умолчанию объектов. Поскольку ссылка не имеет значения по умолчанию, создание такого массива семантически запрещено.

Это правило также применяется к структурам/классам, которые не имеют конструктора по умолчанию. Следующий пример кода не компилируется:

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

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

Ответ 14

Собственно, это смесь синтаксиса C и С++.

Вы должны либо использовать чистые C-массивы, которые не могут быть ссылками, так как ссылки являются частью только С++. Или, вы идете на С++ и используете для этого цели класс std::vector или std::array.

Что касается отредактированной части: даже если struct является элементом из C, вы определяете конструктор и операционные функции, которые делают его С++ class. Следовательно, ваш struct не будет компилироваться в чистом C!

Ответ 15

По простой причине массивы ссылок не могут существовать! Ссылки - это объекты времени компиляции. Значение они заменяются соответствующими адресами во время компиляции. Теперь скажем, что вы создали массив массивов ссылок [].

И некоторые, где в коде вы сделали массив [2], это было бы хорошо. Компилятор может просто посмотреть на третий инициализатор из массива и заменить его.

Но теперь скажите, что вы сделали массив [i], что он заменит? Информация о я отсутствует.

Случай с указателями отличается. Они являются фактическими переменными, которые имеют выделенную им память и разрешаются во время выполнения, если вы указали *. Следовательно, если у вас есть массив указателей и массив * [i], он будет действителен, так как во время выполнения есть информация о i.

Я надеюсь, что он ответит на запрос.