validar - Constructor C++: basura mientras se inicia la referencia de const
validar codigo c++ (4)
Dejaré que mi compilador responda este:
$ g++ -std=c++98 -Wall -Wextra -pedantic test.cpp
test.cpp: In constructor ''X::X()'':
test.cpp:9:26: warning: a temporary bound to ''X::b'' only persists until the constructor exits [-Wextra]
$
Deberías activar las advertencias en tu compilador también.
¿Qué pasa con este código? ¿Por qué recibo una respuesta incorrecta?
class X
{
private:
const int a;
const int& b;
public:
X(): a(10) , b(20)
{
// std::cout << "constructor : a " << a << std::endl;
// std::cout << "constructor : b " << b << std::endl;
}
void display()
{
std::cout << "display():a:" << a << std::endl;
std::cout << "display():b:" << b << std::endl;
}
};
int
main(void)
{
X x;
x.display();
return 0;
}
El código anterior me dará el resultado como
display():a:10
display():b:1104441332
Pero si elimino las 2 líneas comentadas dentro del constructor predeterminado, me da el resultado correcto que es
constructor : a 10
constructor : b 20
display():a:10
display():b:20
por favor ayuda, gracias
Estás vinculando el const&
a un temporal, que no vive más allá de la llamada al constructor. El estándar C ++ 03 dice específicamente "un límite temporal a un miembro de referencia en el inicializador de ctor de un constructor (12.6.2) persiste hasta que el constructor salga" (12.2 / 5 "Objetos temporales").
Por lo tanto, su código tiene un comportamiento indefinido; es posible que no tenga sentido o que parezca que está "funcionando".
FWIW, MSVC 2010 da la siguiente advertencia en ese código:
C:/temp/test.cpp(12) : warning C4413: ''X::b'' : reference member is initialized to a temporary that doesn''t persist after the constructor exits
b
refiere a un temporal. Lo que ha leído (al imprimir) es una ubicación no válida en el momento en que se lee, ya que técnicamente el 20
temporal ha salido del alcance.
Para explicar resultados inconsistentes:
Es un comportamiento indefinido. Lo que ves puede ser diferente si tú:
- cambia tu compilador
- cambiar la configuración de tu compilador
- construir para otra arquitectura
- cambia el diseño de miembros de tu clase
- agrega o elimina cosas de la región de la memoria cerca de la instancia de
x
- etc.
Siempre debes siempre evitar el comportamiento indefinido.
Pero, ¿por qué cambiaría el valor? Su referencia probablemente se refiere a una dirección de pila que ha sido reescrita (por ejemplo, reutilizada) para el momento en que se imprime.
Está inicializando b
como una referencia a un temporal .
El valor 20
se crea y existe solo para el alcance del constructor.
El comportamiento del código después de esto es muy interesante: en mi máquina, obtengo valores diferentes de los que publicó, pero el comportamiento fundamental sigue siendo no determinista.
Esto se debe a que, cuando el valor al cual los puntos de referencia quedan fuera del alcance, comienza a hacer referencia a la memoria basura, lo que le da un comportamiento impredecible.
Ver ¿Una referencia constante prolonga la vida de un temporal? ; la respuesta https://.com/a/2784304/383402 enlaza con la sección relevante del estándar C ++, específicamente el siguiente texto:
A temporary bound to a reference member in a constructor’s ctor-initializer
(12.6.2) persists until the constructor exits.
Esta es la razón por la que siempre obtienes el valor correcto en la impresión dentro del constructor, y raramente (¡pero posiblemente a veces!) Después. Cuando el constructor sale, la referencia cuelga y todas las apuestas están desactivadas.