c++ - págs - hotel p 1990 estadística elemental 7ma ed méxico cecsa
¿Por qué las matrices de referencias son ilegales? (15)
¡Por una simple razón, las matrices de referencias no pueden existir! Las referencias son entidades de tiempo de compilación. Lo que significa que se reemplazan con las direcciones apropiadas durante el tiempo de compilación. Ahora di que hiciste y una matriz de referencias array [].
Y en algún lugar del código que hiciste array [2], estaría bien. El compilador solo puede ver el tercer inicializador de la matriz y reemplazar la dirección.
Pero ahora di que hiciste array [i], ¿con qué va a reemplazar? No hay información sobre i.
El caso con punteros es diferente. Son variables reales que tienen memoria asignada a ellos y se resuelven durante el tiempo de ejecución si lo hace * puntero. Por lo tanto, si tiene una matriz de punteros y hace * matriz [i], será válida ya que hay información acerca de i durante la ejecución.
Espero que responda la consulta.
El siguiente código no compila.
int a = 1, b = 2, c = 3;
int& arr[] = {a,b,c,8};
¿Qué dice el estándar de C ++ sobre esto?
Sé que podría declarar una clase que contiene una referencia, 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 usar struct cintref
lugar de const int &
simular una matriz de referencias.
Comenta tu edición:
La mejor solución es std::reference_wrapper
.
Detalles: http://www.cplusplus.com/reference/functional/reference_wrapper/
Ejemplo:
#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;
}
Considere una variedad de punteros. Un puntero es realmente una dirección; por lo tanto, cuando inicializa la matriz, le está diciendo análogamente a la computadora: "asigne este bloque de memoria para contener estos números X (que son direcciones de otros elementos)". Entonces, si cambia uno de los indicadores, solo está cambiando lo que apunta; sigue siendo una dirección numérica que se encuentra en el mismo lugar.
Una referencia es análoga a un alias. Si tuvieras que declarar una serie de referencias, básicamente estarías diciéndole a la computadora, "asigna esta gota de memoria amorfa que consiste en todos estos diferentes elementos diseminados por todos lados".
Creo que la respuesta es muy simple y tiene que ver con las reglas semánticas de las referencias y cómo se manejan las matrices en C ++.
En resumen: las referencias pueden considerarse como estructuras que no tienen un constructor predeterminado, por lo que se aplican las mismas reglas.
1) Semánticamente, las referencias no tienen un valor predeterminado. Las referencias solo se pueden crear al hacer referencia a algo. Las referencias no tienen un valor para representar la ausencia de una referencia.
2) Al asignar una matriz de tamaño X, el programa crea una colección de objetos inicializados por defecto. Como la referencia no tiene un valor predeterminado, la creación de dicha matriz es semánticamente ilegal.
Esta regla también se aplica a las estructuras / clases que no tienen un constructor predeterminado. El siguiente ejemplo de código no se compila:
struct Object
{
Object(int value) { }
};
Object objects[1]; // Error: no appropriate default constructor available
Cuando almacena algo en una matriz, su tamaño debe conocerse (ya que la indexación de la matriz depende del tamaño). Según el estándar de C ++ No se especifica si una referencia requiere o no almacenamiento, por lo que no sería posible indexar una matriz de referencias.
Dado int& arr[] = {a,b,c,8};
, ¿qué es sizeof(*arr)
?
En todas partes, una referencia se trata simplemente como la cosa misma, por lo que sizeof(*arr)
debería simplemente ser sizeof(int)
. Pero esto haría que la aritmética del puntero de matriz en esta matriz fuera errónea (suponiendo que las referencias no tengan el mismo ancho es ints). Para eliminar la ambigüedad, está prohibido.
En realidad, esta es una mezcla de sintaxis C y C ++.
Debería usar matrices en C puro, que no pueden ser de referencias, ya que la referencia es solo parte de C ++. O utiliza la forma C ++ y usa la clase std::vector
o std::array
para su propósito.
En cuanto a la parte editada: aunque la struct
es un elemento de C, usted define un constructor y funciones de operador, que lo convierten en una class
C ++. ¡Por consiguiente, su struct
no compilaría en C puro!
Esta es una discusión interesante. Claramente las matrices de ref son completamente ilegales, pero en mi humilde opinión la razón por la cual 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 objeta eso, trate de crear instancias de algunas clases de plantilla stl usando una matriz como un 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 arreglos de matrices. Las referencias tienen un tamaño que el compilador puede y debe calcular: no se puede hacer sizeof () de una referencia, pero puede hacer una estructura que no contenga más que referencias. Tendrá un tamaño suficiente para contener todos los punteros que implementan las referencias. No 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, puede agregar esta línea a la definición de 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 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
Ahora bien, esta no es una matriz real, es una sobrecarga del operador; no hará cosas que las matrices normalmente hacen 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 (a) es difícil establecer para más de 3 o 4 elementos, y (b) está haciendo un cálculo usando un montón de?: Que se puede hacer usando indexación (no con indización C-puntero-cálculo-semántica normal) , pero indización de todos modos). Me gustaría ver un tipo muy limitado de ''matriz de referencia'' que realmente pueda hacer esto. Es decir, una serie de referencias no se trataría como una serie general de elementos que son referencias, sino que sería una nueva "matriz de referencia" que se correlaciona efectivamente con una clase generada internamente similar a la anterior (pero que desafortunadamente no se puede hacer con plantillas).
esto probablemente funcionaría, si no te importa este tipo de desagradable: refundir ''* this'' como una matriz de int * ''s y devolver una referencia hecha de uno: (no recomendado, pero muestra cómo el'' arreglo ''apropiado) trabajaría):
int & operator[]( int i ) { return *(reinterpret_cast<int**>(this)[i]); }
Las referencias no son objetos. No tienen almacenamiento propio, solo hacen referencia a objetos existentes. Por esta razón, 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 una struct
con un miembro de referencia como objetos en matrices si proporciona una inicialización explícita para todos los miembros de referencia para todas las instancias de struct
. Las referencias no pueden ser inicializadas por defecto.
Editar: como notas de jia3ep, en la sección estándar de declaraciones hay una prohibición explícita en las matrices de referencias.
Porque, como muchos han dicho aquí, las referencias no son objetos. son simplemente alias. Es cierto que algunos compiladores podrían implementarlos como punteros, pero el estándar no lo obliga / especifica eso. Y como las referencias no son objetos, no puede señalarlos. Almacenar elementos en una matriz significa que hay algún tipo de dirección de índice (es decir, apuntando a elementos en un índice determinado); y es por eso que no puede tener matrices de referencias, porque no puede señalarlas.
Use boost :: reference_wrapper, o boost :: tuple en su lugar; o solo punteros.
Puede acercarse bastante con esta estructura de plantilla. Sin embargo, debe inicializar con expresiones que son punteros a T, en lugar de T; por lo tanto, aunque puede hacer fácilmente un ''fake_constref_array'' de forma similar, no podrá vincularlo a rvalues como se hace en el ejemplo del 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}
Respondiendo a su pregunta sobre el estándar, puedo citar el Estándar C ++ §8.3.2 / 4 :
No habrá referencias a referencias, ni arreglos de referencias , ni punteros a las referencias.
Solo para agregar a toda la conversación. Dado que las matrices requieren ubicaciones de memoria consecutivas para almacenar el elemento, entonces si creamos una matriz de referencias, entonces no se garantiza que estén en una ubicación de memoria consecutiva, por lo que acceder será un problema y, por lo tanto, no podemos aplicar todas las operaciones matemáticas formación.
Un objeto de referencia no tiene tamaño. Si escribe sizeof(referenceVariable)
, le dará el tamaño del objeto referenciado por referenceVariable
, no el de la referencia en sí. No tiene tamaño propio, por lo que el compilador no puede calcular cuánto tamaño requerirá la matriz.
Una matriz es implícitamente convertible a un puntero, y el puntero a referencia es ilegal en C ++