¿Por qué esto:
#include <string>
#include <iostream>
using namespace std;
class Sandbox
{
public:
Sandbox(const string& n) : member(n) {}
const string& member;
};
int main()
{
Sandbox sandbox(string("four"));
cout << "The answer is: " << sandbox.member << endl;
return 0;
}
Dar salida de:
La respuesta es:
En vez de:
La respuesta es: cuatro
cout << "The answer is: " << Sandbox(string("four")).member << endl;
, entonces estaría garantizado que funcionaría.SandBox::member
se lee, la cadena temporal todavía está viva .string("four")
se destruye al final de la expresión completa y no después de queSandbox
salga el constructor? La respuesta de Potatoswatter dice que un enlace temporal a un miembro de referencia en un ctor-initializer del constructor (§12.6.2 [class.base.init]) persiste hasta que el constructor sale.Respuestas:
Solo las
const
referencias locales prolongan la vida útil.El estándar especifica dicho comportamiento en §8.5.3 / 5, [dcl.init.ref], la sección sobre inicializadores de declaraciones de referencia. La referencia en su ejemplo está vinculada al argumento del constructor
n
, y deja de ser válida cuando el objeton
está fuera de alcance.La extensión de por vida no es transitiva a través de un argumento de función. §12.2 / 5 [clase.temporal]:
fuente
member
está vinculado a un temporal, porque la inicializaciónmember
conn
medios para unirsemember
al mismo objeton
está vinculado, y de hecho es un objeto temporal en este caso.const
cuantificador.Aquí está la forma más simple de explicar lo que sucedió:
En main () creaste una cadena y la pasaste al constructor. Esta instancia de cadena solo existía dentro del constructor. Dentro del constructor, asignó miembro para apuntar directamente a esta instancia. Cuando cuando el ámbito abandonó el constructor, la instancia de cadena se destruyó, y el miembro luego señaló un objeto de cadena que ya no existía. Hacer que Sandbox.member apunte a una referencia fuera de su alcance no mantendrá esas instancias externas dentro del alcance.
Si desea arreglar su programa para mostrar el comportamiento que desea, realice los siguientes cambios:
Ahora temp pasará fuera del alcance al final de main () en lugar de al final del constructor. Sin embargo, esta es una mala práctica. Su variable miembro nunca debe ser una referencia a una variable que existe fuera de la instancia. En la práctica, nunca se sabe cuándo esa variable estará fuera de alcance.
Lo que recomiendo es definir Sandbox.member como un
const string member;
Esto copiará los datos del parámetro temporal en la variable miembro en lugar de asignar la variable miembro como el parámetro temporal en sí.fuente
const string & temp = string("four"); Sandbox sandbox(temp); cout << sandbox.member << endl;
¿seguirá funcionando?const string &temp = string("four");
da el mismo resultado queconst string temp("four");
, a menos que lo usedecltype(temp)
específicamenteHowever, this is bad practice.
- ¿por qué? Si tanto la temperatura como el objeto que lo contiene usan almacenamiento automático en el mismo ámbito, ¿no es 100% seguro? Y si no haces eso, ¿qué harías si la cadena es demasiado grande y demasiado costosa para copiar?Técnicamente hablando, este programa no requiere que realmente envíe nada a la salida estándar (que es una secuencia almacenada para empezar).
El
cout << "The answer is: "
bit se emitirá"The answer is: "
en el búfer de stdout.Luego, el
<< sandbox.member
bit proporcionará la referencia colganteoperator << (ostream &, const std::string &)
, que invoca un comportamiento indefinido .Debido a esto, no se garantiza que suceda nada. El programa puede funcionar aparentemente bien o puede fallar sin siquiera descargar stdout, lo que significa que el texto "La respuesta es:" no aparecería en su pantalla.
fuente
"The answer is: "
se escribirá en cualquier lugar.Debido a que su cadena temporal quedó fuera de alcance una vez que el constructor de Sandbox regresó, y la pila ocupada por ella fue reclamada para otros fines.
En general, nunca debe retener referencias a largo plazo. Las referencias son buenas para argumentos o variables locales, nunca miembros de la clase.
fuente
te estás refiriendo a algo que ha desaparecido. Lo siguiente funcionará
fuente