c++ - lib - prefix c jsp
¿Se usarán goto variables de fuga? (1)
Advertencia: esta respuesta pertenece solo a C ++; las reglas son bastante diferentes en C.
¿No se filtrará
x
?
No absolutamente no.
Es un mito que goto
es una construcción de bajo nivel que le permite anular los mecanismos de alcance incorporados de C ++. (En todo caso, es longjmp
que puede ser propenso a esto).
Considere los siguientes mecanismos que le impiden hacer "cosas malas" con etiquetas (que incluyen etiquetas de case
).
1. Alcance de la etiqueta
No puedes saltar a través de funciones:
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
// error: label ''lol'' used but not defined
[n3290: 6.1/1]:
[..] El alcance de una etiqueta es la función en la que aparece. [..]
2. Inicialización de objetos
No puede saltar a través de la inicialización de objetos :
int main() {
goto lol;
int x = 0;
lol:
return 0;
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘int x’
Si retrocede a través de la inicialización del objeto, entonces se destruye la "instancia" previa del objeto :
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
int x = 0;
lol:
T t;
if (x++ < 5)
goto lol;
}
// Output: *T~T*T~T*T~T*T~T*T~T*T~T
[n3290: 6.6/2]:
[..] La transferencia de un bucle, de un bloque o de una variable inicializada con duración de almacenamiento automática implica la destrucción de objetos con duración de almacenamiento automático que están en el alcance en el punto transferido desde pero no en el punto transferido a. [..]
No puede saltar al alcance de un objeto , incluso si no se ha inicializado explícitamente:
int main() {
goto lol;
{
std::string x;
lol:
x = "";
}
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘std::string x’
... excepto para ciertos tipos de objetos , que el lenguaje puede manejar independientemente porque no requieren una construcción "compleja":
int main() {
goto lol;
{
int x;
lol:
x = 0;
}
}
// OK
[n3290: 6.7/3]:
es posible transferir a un bloque, pero no de una manera que evite las declaraciones con inicialización. Un programa que salta desde un punto donde una variable con una duración de almacenamiento automática no está en alcance hasta un punto en el que está dentro del alcance está mal formado a menos que la variable tenga tipo escalar, tipo de clase con un constructor trivial predeterminado y un destructor trivial, versión cv-calificada de uno de estos tipos, o una matriz de uno de los tipos anteriores y se declara sin un inicializador. [..]
3. El salto se atiene al alcance de otros objetos
Del mismo modo, los objetos con duración de almacenamiento automático no se "filtran" cuando sale de su alcance :
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
{
T t;
goto lol;
}
lol:
return 0;
}
// *T~T
[n3290: 6.6/2]:
salir de un alcance ([n3290: 6.6/2]:
realice), los objetos con duración de almacenamiento automático (3.7.3) que se han construido en ese alcance se destruyen en el orden inverso al de su construcción. [..]
Conclusión
Los mecanismos anteriores aseguran que goto
no le permite romper el idioma.
Por supuesto, esto no significa automáticamente que "deberías" usar goto
para un problema determinado, pero sí significa que no es tan "malo" como el mito común lleva a la gente a creer.
¿Es cierto que goto
salta a través de bits de código sin llamar destructores y cosas?
p.ej
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
¿No se filtrará x
?