2012-02-15 7 views
40

He leído en todas partes que una referencia tiene que inicializarse en ese momento y no se puede volver a inicializar de nuevo.¿Podemos reasignar la referencia en C++?

Para probar mi comprensión, he escrito el siguiente pequeño programa. Parece como si realmente hubiera logrado reasignar una referencia. ¿Puede alguien explicarme qué está sucediendo realmente en mi programa?

#include <iostream> 
#include <stdio.h> 
#include <conio.h> 

using namespace std; 

int main() 
{ 
    int i = 5, j = 9; 

    int &ri = i; 
    cout << " ri is : " << ri <<"\n"; 

    i = 10; 
    cout << " ri is : " << ri << "\n"; 

    ri = j; // >>> Is this not reassigning the reference? <<< 
    cout << " ri is : " << ri <<"\n"; 

    getch(); 
    return 0; 
} 

El código compila bien y la salida es como espero:

ri is : 5 
ri is : 10 
ri is : 9 

Respuesta

42

ri = j; // >>> Is this not reassigning the reference? <<<

No, ri sigue siendo una referencia a i - se puede demostrar esto imprimiendo &ri y &i y ver que son la misma dirección.

Lo que hizo es modificar ia través de la referencia ri. Imprime i después, y verás esto.

Además, para comparar, si crea un const int &cri = i;, no le permitirá asignarlo.

+0

¿Por qué 'const int & cri = i' no está permitido? ¿En qué línea no puedes escribir eso? Causa para mí el compilador permite insertar dicha línea en cualquier lugar. ¡Aparte de eso, es una respuesta clara y concisa! – mercury0114

+0

No he dicho que no esté permitido, como has observado, tomar una referencia constante a una variable no const está bien. Dije que no te dejaría asignar a eso, lo que significa que no puedes cambiar la variable original a través de una referencia constante, como lo hizo OP con 'ri'. – Useless

+0

Oh, cierto, ahora veo lo que querías decir. – mercury0114

3

Cuando se asigna una referencia a algo que en realidad se asigna el valor al objeto de referencia está enlazado. Así que esto:

ri=j; 

tiene el mismo efecto que

i = j; 

tendría porque ri está obligado a i. Entonces cualquier acción en ri se ejecuta en i.

3

No está asignando la referencia al ejecutar ri = j;. De hecho, está asignando j a i. Intente imprimir i después de la línea y verá que i cambió el valor.

6

Parece que realmente logré reasignar una referencia. ¿Es eso verdad?

No, usted no tiene. En realidad, estás reasignando el valor y no estás volviendo a vincular la referencia.

En su ejemplo, cuando lo hace int &ri = i;, ri está obligado a i durante su vida útil. Cuando lo haga ri = j;, simplemente está asignando el valor de j a ri. ri sigue siendo una referencia al i! Y el resultado es el mismo resultado que si se hubiera escrito en lugar i = j;

Si usted entiende punteros bien, entonces siempre se piensa en la referencia como una interpretación analógica de T* const donde T es cualquier tipo.

0

OP solicitó la modificación del objeto al que se hace referencia mediante la asignación a la referencia y se dijo muy correctamente que esto cambió el objeto de referencia, no la referencia. Ahora hice un intento más conmovedor de cambiar realmente la referencia y encontré cosas potencialmente desagradables. Primero el código. Intenta reasignar a la referencia var un objeto recién creado, luego altera el objeto referencia referenciado, encuentra que esto no se refleja en los objetos aparentemente referenciados y concluye que podemos tener un caso de un puntero colgante en C++. Perdón por el código apresuradamente compuesto.

using namespace std; 
vector<int>myints; 

auto &i = myints.emplace_back(); // allocate and reference new int in vector 
auto myintsaddr = &myints; auto myintfrontaddr = &myints.front(); // for future reference 
i = 1;        // assign a value to the new int through reference 
cout << hex << "address of i: 0x" << &i << " equals " << "address of 
myints.back(): 0x" << &myints.back() << '.' << endl; // check reference as expected 
i = myints.emplace_back();  // allocate new int in vector and assign to old reference variable 
i = 2;       // give another value to i 
cout << "i=" << i << ", myints={" << myints[0] << ", "<< myints[1] << '}' << endl; // any change to potentially referenced objects? 
cout << hex << "&i: 0x" << &i << " unequal to " << "&myints.back(): 0x" << &myints.back() << " as well as &myints.front(): 0x" << &myints.front() << endl; 
cout << "Myints " << (myintsaddr== &myints?"not ":"") << "relocated from " << myintsaddr << " to " << &myints << endl; 
cout << "Myints front() " << (myintfrontaddr == &myints.front() ? "not " : "") << "relocated from " << myintfrontaddr << " to " << &myints.front() << endl; 

Salida:

address of i: 0x0063C1A0 equals address of myints.back(): 0x0063C1A0. 
i=2, myints={1, 0} 
&i: 0x0063C1A0 unequal to &myints.back(): 0x0063F00C as well as &myints.front(): 0x0063F008 
Myints not relocated from 0039FE48 to 0039FE48 
Myints front() relocated from 0063C1A0 to 0063F008 

Conclusión: por lo menos en mi caso (VS2017), la referencia se ha mantenido la misma dirección exacta en la memoria, pero los valores de referencia (parte del vector) se han reasignado en otra parte. Referencia i puede estar colgando.