¿Por qué son ilegales las matrices de referencias?

Resuelto Alexey Malistov asked hace 15 años • 14 respuestas

El siguiente código no se compila.

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

¿Qué dice el estándar C++ sobre esto?

Sé que podría declarar una clase que contenga una referencia y luego crear una matriz de esa clase, como se muestra a continuación. Pero realmente quiero saber por qué el código anterior no se compila.

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

Es posible utilizar struct cintrefen lugar de const int &simular una serie de referencias.

Alexey Malistov avatar Jul 22 '09 17:07 Alexey Malistov
Aceptado

Respondiendo a su pregunta sobre el estándar, puedo citar el Estándar C++ §8.3.2/4 :

No habrá referencias a referencias, ni matrices de referencias , ni punteros a referencias.

Esto se debe a que las referencias no son objetos y no ocupan memoria, por lo que no tienen la dirección. Puedes considerarlos como alias de los objetos. Declarar una serie de nada no tiene mucho sentido.

Kirill V. Lyadvinsky avatar Jul 22 '2009 10:07 Kirill V. Lyadvinsky

Las referencias no son objetos. No tienen almacenamiento propio, solo hacen referencia a objetos existentes. Por este motivo, no tiene sentido tener matrices de referencias.

Si desea un objeto liviano que haga referencia a otro objeto, puede usar un puntero. Solo podrá utilizar a structcon un miembro de referencia como objetos en matrices si proporciona una inicialización explícita para todos los miembros de referencia para todas las structinstancias. Las referencias no se pueden inicializar de forma predeterminada.

Editar: Como señala jia3ep, en la sección estándar sobre declaraciones hay una prohibición explícita de conjuntos de referencias.

CB Bailey avatar Jul 22 '2009 10:07 CB Bailey

Esta es una discusión interesante. Claramente, las matrices de referencias son completamente ilegales, pero en mi humilde opinión, la razón no es tan simple como decir "no son objetos" o "no tienen tamaño". Señalaría que las matrices en sí mismas no son objetos completos en C/C++; si se opone a eso, intente crear instancias de algunas clases de plantilla stl usando una matriz como parámetro de plantilla de 'clase' y vea qué sucede. No puede devolverlos, asignarlos, pasarlos como parámetros. (un parámetro de matriz se trata como un puntero). Pero es legal hacer matrices de matrices. Las referencias tienen un tamaño que el compilador puede y debe calcular; no se puede hacer sizeof() una referencia, pero se puede crear una estructura que no contenga nada más que referencias. Tendrá un tamaño suficiente para contener todos los punteros que implementan las referencias. No se puede crear una instancia de dicha estructura sin inicializar todos los miembros:

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

De hecho, puedes agregar esta línea a la definición de la estructura.

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

...y ahora tengo algo que se parece MUCHO a una serie de referencias:

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

Ahora bien, esto no es una matriz real, es una sobrecarga del operador; no hará cosas que normalmente hacen las matrices como sizeof(arr)/sizeof(arr[0]), por ejemplo. Pero hace exactamente lo que quiero que haga una serie de referencias, con C++ perfectamente legal. Excepto que (a) es complicado configurar más de 3 o 4 elementos, y (b) está haciendo un cálculo usando un montón de ?: lo cual podría hacerse usando indexación (no con indexación semántica de cálculo de puntero C normal). , pero indexando de todos modos). Me gustaría ver un tipo de 'matriz de referencia' muy limitada que realmente pueda hacer esto. Es decir, una matriz de referencias no se trataría como una matriz general de cosas que son referencias, sino que sería una nueva 'matriz de referencias' que efectivamente se asigna a una clase generada internamente similar a la anterior (pero que lamentablemente no puedes hacerlo con plantillas).

esto probablemente funcione, si no le importa este tipo de cosas desagradables: reformule '*this' como una matriz de int * y devuelva una referencia hecha a partir de uno: (no recomendado, pero muestra cómo funciona la 'matriz' adecuada trabajaría):

 int & operator[]( int i ) { return *(reinterpret_cast<int**>(this)[i]); }
greggo avatar Nov 11 '2011 00:11 greggo