una tipos significado programacion funciones declaracion declara datos constantes constante como c++ goto local-variables register-allocation

c++ - tipos - Ir a una definición de variable anterior: ¿qué sucede con su valor?



tipos de variables en c++ y su significado (4)

Aquí hay una pregunta que me pregunté. Dado el siguiente código, ¿podemos estar seguros de su salida?

void f() { int i = 0; z: if(i == 1) goto x; else goto u; int a; x: if(a == 10) goto y; u: a = 10; i = 1; goto z; y: std::cout << "finished: " << a; }

¿Se garantiza que este resultado finished: 10 según el estándar C ++? ¿O puede el compilador ocupar el registro en el que se almacena a, cuando va a un lugar antes de a ?


¿Se garantiza la salida finished: 10 según el estándar C ++?

Creo que sí, ¡hay que hacerlo!

Por qué ? Debido a vive desde su declaración hasta el final de su alcance (final de la función) y, por definición, solo se puede inicializar una vez y desde allí conservar su valor hasta la destrucción que se encuentra al final de la función.


6.7 / 3 dice que

Un programa que salta de un punto donde una variable local con duración de almacenamiento automático no está dentro del alcance a un punto donde está dentro del alcance está mal formado a menos que la variable tenga un tipo de POD (3.9) y se declare sin un inicializador (8.5).

Así que eso debería estar bien.

Luego en 6.6 / 2:

Al salir de un alcance (aunque se haya realizado), se llama a los destructores (12.4) para todos los objetos construidos con duración de almacenamiento automático (3.7.2) (objetos nombrados o temporales) que se declaran en ese alcance, en el orden inverso a su declaración.

Ahora bien, esto me implica que a es a brindis cuando vuelves a z y no puedes ofrecer ninguna garantía sobre cómo se comportará la declaración de no inicializador de a la segunda vez que se ejecute.

Ver 6.7 / 2:

Las variables con duración de almacenamiento automático (3.7.2) se inicializan cada vez que se ejecuta su declaración de declaración. Las variables con la duración del almacenamiento automático declarada en el bloque se destruyen al salir del bloque (6.6).

Me parece que no hay una garantía de que obtendrás 10, aunque parece difícil imaginar un compilador en el que ese no sería el caso.


No está permitido renunciar a una definición de variable. Debería ser un error.


Nota: Lea los comentarios de este primero. Johannes más o menos derribó toda mi discusión con una cita estándar bien colocada. ;-)

No tengo el estándar C ++ disponible, por lo que tengo que extrapolar del estándar C.

Sorprendentemente (para mí), el capítulo 6.2.1 El alcance de los identificadores no dice nada sobre el alcance de un identificador que comienza en el momento de su declaración (como lo habría adivinado). int a , en su ejemplo, tiene un ámbito de bloque , que "termina al final del bloque asociado", y eso es todo lo que se dice al respecto. el capítulo 6.8.6.1 La declaración de goto dice que "una declaración de goto no saltará desde fuera del alcance de un identificador que tenga un tipo modificado de forma variable hasta dentro del alcance de ese identificador", sino que su salto saltará solo dentro del bloque (y Por lo tanto, el alcance de int a , que parece estar bien en lo que se refiere a ISO / IEC 9899: 1999.

Estoy bastante sorprendido por esto ...

Edición n. ° 1: un rápido google después puse mis manos en el borrador final de C ++ 0x. La declaración relevante, creo, es esto aquí (6.7 Declaración de la declaración , destacando la mía):

Es posible transferir a un bloque, pero no de una manera que evite las declaraciones con la inicialización . Un programa que salta de un punto donde una variable con duración de almacenamiento automático no está dentro del alcance a un punto donde está dentro del alcance está mal formado a menos que la variable tenga tipo escalar , tipo de clase con un constructor predeterminado trivial y un destructor trivial, un La versión cv calificada de uno de estos tipos, o una matriz de uno de los tipos anteriores y se declara sin un inicializador .

Creo que su código está bien para los estándares. Pero a tope feo, fíjate. ;-)

Edit # 2: Leyendo su comentario sobre la posible destrucción de int a debido al salto hacia atrás, encontré esto (6.6 declaraciones de Jump , resaltando las mías):

La transferencia fuera de un bucle, fuera de un bloque, o retrocediendo una variable inicializada con duración de almacenamiento automática implica la destrucción de objetos con duración de almacenamiento automática que están dentro del alcance en el punto transferido pero no en el punto transferido.

Uno, int a no está "inicializado", y no es un objeto si entiendo correctamente la terminología estándar.