2011-07-26 11 views
13

Nota: Estoy usando el compilador de g ++ (que según tengo entendido es bastante bueno y se supone que es bastante parecido al estándar).Al declarar una referencia a una matriz de Ints, ¿por qué debe ser una referencia a un puntero const?


Digamos que usted ha declarado una matriz de enteros:

int a[3] = { 4, 5, 6 }; 

Ahora digamos que usted realmente desea declarar una referencia a esa matriz (no importa qué, que no sea el Bjarne dice el lenguaje lo admite)

Caso 1 - Si se intenta:

int*& ra = a; 

entonces las vigas del compilador y dice:

"invalid initialization of non-const reference of type `int*&' from a temporary of type `int*'" 

Lo primero es lo primero, ¿por qué es 'a' una variable temporal (es decir, no hace que tienen un lugar en la memoria?) ...

de todos modos, bien, cada vez que veo un error de no constante, trato de tirar en una const ...

Caso 2 - si se intenta:

int*const&rca = a; //wish I knew where the spaces should go (but my other post asking about this sort of protocol got a negative rank while many of the answers got ranked highly -- aha! there are stupid questions!) 

entonces todo es fresco, compila, y se obtiene una referencia a la matriz.

Caso 3 - Ahora aquí es otra cosa que compilará:

int* justSomeIntPointer = a; //LINE 1 
int*& rpa = justSomeIntPointer; //LINE 2 

Esto también le da una referencia a la matriz original.

Así que aquí está mi pregunta: ¿En qué punto el nombre de una matriz estáticamente declarada se convierte en un puntero const? Me parece recordar que el nombre de una matriz de ints es también un puntero-a-int, pero no recuerdo que haya sido un const-pointer-to-int ...

Parece que el caso 1 falla porque la referencia declarada (ra) no es const-puntero, lo que puede significar que 'a' ya era un const-pointer-to-int para empezar.

Parece que el Caso 2 funciona porque la referencia declarada (rca) ya es un const-pointer-to-int.

El caso 3 también funciona, lo cual es bueno, pero ¿por qué? ¿En qué punto el puntero supuesto-a-int (es decir, el nombre de la matriz 'a') se convierte en un puntero const? ¿Sucede cuando lo asigna a un int * (LINE 1), o sucede cuando asigna ese int * a un int * & (LINE 2)?

Espero que esto tenga sentido. Gracias.

Respuesta

27
int*& ra = a; 

int* es un tipo de puntero, no un tipo de matriz. Es por eso que no se vinculará a a, que tiene el tipo int[3].

int* const& ra = a; 

obras, porque equivale a

int* const& ra = (int*)a; 

Es decir, un temporal puntero se crea conceptualmente en el lado derecho de la asignación y este temporal se unen entonces a ra. Así que al final, esto no es mejor que:

int* ra = a; 

donde ra es en realidad un puntero al primer elemento de la matriz, no una referencia a la matriz.

Declarar una referencia a una matriz de la manera fácil:

typedef int array_type[3]; 
array_type& ra = a; 

La forma no-como-fácil:

int (&ra)[3] = a; 

La forma 11-fácil C++:

auto& ra = a; 

¿En qué punto el nombre de una matriz estáticamente declarada se convierte en un puntero const? Parece recordar que el nombre de una matriz de ints es también un puntero-a-int, pero no recuerdo que haya sido un const-pointer-to-int ...

Este es el pregunta correcta para preguntar! Si entiende cuándo ocurre la descomposición de matriz a punta, entonces está a salvo. En pocas palabras, hay dos cosas a tener en cuenta:

  • decaimiento ocurre cuando se intenta realizar cualquier tipo de 'copia' (porque C no permite matrices para ser copiados directamente)
  • la caries es una especie de conversión y puede suceda cada vez que se permita una conversión: cuando los tipos no coinciden

El primer tipo normalmente ocurre con plantillas. . Entonces, dado template<typename T> pass_by_value(T);, entonces pass_by_value(a) realidad pasará un int*, debido a que la matriz de tipo int[3] no se puede copiar en

En cuanto a la segunda, que ya ha visto en acción: esto sucede en el segundo caso cuando int* const& no se puede vincular a int[3], pero puede vincularse a un int* temporal, por lo que se produce la conversión.

-2

a es una variable temporal porque la declaró en la pila y no en el montón utilizando un malloc o una nueva.

+0

también lo son variables temporales siempre const? – Jimmy

+3

@Jimmy: los temporales no siempre son const, pero el lenguaje prohíbe vincular uno directamente a una referencia no constante. La matriz 'a' no es temporal, sin embargo, es el puntero que resulta de la conversión de matriz a puntero que es temporal. –

+0

Declarado en la pila significa "tiene una duración de almacenamiento automática", es decir, sale del alcance cuando su bloque/objeto contiene, no "temporalmente". Pocos consideran tener que administrar manualmente los objetos asignados dinámicamente para ser un punto positivo. Lo último que necesitamos es otra idea falsa sobre por qué la asignación dinámica es mejor. Este es especialmente malo porque invoca una definición falsa de _temporary_, un término que tiene un significado muy bien definido y diferente. –

0

¿En qué punto el nombre de una matriz estáticamente declarada se convierte en un puntero const? Me parece recordar que el nombre de una matriz de ints es también un puntero-a-int, pero no recuerdo que haya sido un const-pointer-to-int ...

Porque escribiste el valores allí mismo en el archivo cpp, es por eso que es constante.

sólo puede utilizar:

const int *pToArray = a; 

o

const int *pToArray = (const int*)&a[0]; 
2

El gran error (también una muy buena pregunta de la entrevista) que la mayoría de la gente hace es que piensan que el nombre de una matriz es equivalente a un puntero. Eso no es verdad. Este error causa muchos errores en los programas de C, especialmente vinculando errores, y son muy difíciles de depurar. La diferencia es esta: el nombre de la matriz, es un puntero el primer elemento de una estructura, la matriz. Sin embargo, el tipo del nombre de la matriz no es un tipo de punta sino un tipo de matriz. Un puntero, por otro lado, es solo un indicador de una cosa sin otra información. El tipo de un puntero es un tipo de punta. Un arraytype tiene otras propiedades como saber si está en la pila o no; por lo tanto, "temporal". El error temporal en su caso proviene de una verificación que impide que una variable temporal se asigne a una referencia. La palabra clave const desactiva esa marca. Un pointertype por otro lado no tiene noción de "temporal". Ahora supongamos que quiere engañar al compilador y asignar una referencia a algo que está en la pila. En ese caso, debe convertirlo en un puntero. ¿Cómo?

int * & ra = & a [0];

en el caso anterior por primera vez obtener el valor y el uso de un (dirección del operador) & haces una pointerType. Ahora un pointertype no tiene información sobre si está en la pila (una variable temporal) o no. Sin embargo, esto hará referencia a un puntero al primer elemento de la matriz. (Por lo tanto, sólo un tipo de puntero, no un ArrayType)

1

Si realmente quieres una referencia a una matriz, entonces debe usar la siguiente:

int a[3] = { 4, 5, 6 }; 
int (&ra)[3] = a; 

Lo que estamos tratando de crear con int *& es una referencia a un puntero a un int. Este no es el mismo tipo. Y a medida que inicializa la referencia con un valor que no puede cambiar (la dirección de la matriz) debe declarar la const del puntero (no las entradas).

1

tiene una matriz de enteros:

int a[3] = { 4, 5, 6 }; 

Ahora, esta línea:

int*& ra = a; 

crea una referencia a un puntero. Como usted crea un puntero temporal (convertido desde la matriz a), el compilador se queja porque la norma prohíbe la asignación de temporales a una referencia.

Así, para solucionarlo, es necesario crear un puntero y, a continuación, asignar a una referencia a un puntero:

int *pa = a; 
int *& rpa = pa; 

referencias constantes pueden contener referencia a los temporales, pero ya lo descubrió.

Lo que solicitó (alrededor referencia a una matriz) - el ejemplo más famoso de crear una referencia a una matriz es la siguiente:

template< typename T, size_t N > 
size_t ArraySize(T (&)[ N ]) 
{ 
    return N; 
} 

Esta función toma una referencia a una matriz y devuelve su tamaño.

8

La palabra "matriz" en C++ se escribe con corchetes []. Si desea declarar algo-array-something en C++, debe tener corchetes en su declaración. Si escribe un asterisco * en su lugar, obtendrá un puntero.Los punteros y matrices son dos cosas diferentes.

Esta es una referencia a un array:

int (&ra) [3] = a; 
Cuestiones relacionadas