Es cierto que goto
salta a través de bits de código sin llamar a los destructores y cosas?
p.ej
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
¿No x
se filtrará?
Es cierto que goto
salta a través de bits de código sin llamar a los destructores y cosas?
p.ej
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
¿No x
se filtrará?
"Won't x be leaked"
significa? El tipo de x
es un tipo de datos integrado. ¿Por qué no eliges un mejor ejemplo?
goto
, piensa que incluso las variables de duración del almacenamiento automático se "filtran" de alguna manera. Que tú y yo sepamos lo contrario está completamente fuera del punto.
int
no puede tener fugas, puede tener fugas . Por ejemplo: void f(void) { new int(5); }
fugas an int
.
Respuestas:
Advertencia: esta respuesta se refiere a C ++ solamente ; las reglas son bastante diferentes en C.
¿No
x
se filtrará?
No absolutamente no.
Es un mito que goto
es una construcción de bajo nivel que le permite anular los mecanismos de alcance integrados de C ++. (En todo caso, es longjmp
que puede ser propenso a esto).
Considere los siguientes mecanismos que le impiden hacer "cosas malas" con las etiquetas (que incluye case
etiquetas).
No puede saltar entre 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. [..]
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, la "instancia" anterior del objeto se destruye :
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 fuera de un bucle, fuera de un bloque o retrocediendo más allá de una variable inicializada con duración de almacenamiento automático implica la destrucción de objetos con duración de almacenamiento automático que están dentro del alcance en el punto transferido pero no en el punto transferido a . [..]
No puede saltar al alcance de un objeto, incluso si no está 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 omita las declaraciones con la inicialización. Un programa que salta desde 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 un tipo escalar, un tipo de clase con un constructor predeterminado trivial y un destructor trivial, un versión calificada por cv de uno de estos tipos, o una matriz de uno de los tipos anteriores y se declara sin un inicializador. [..]
Del mismo modo, los objetos con una duración de almacenamiento automático son no "filtrado" cuando goto
fuera 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]:
Al salir de un alcance (sin importar cómo se haya logrado), 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 de su construcción. [..]
Los mecanismos anteriores aseguran que goto
no le permita romper el lenguaje.
Por supuesto, esto no significa automáticamente que "debería" usarlo goto
para un problema dado, pero sí significa que no es tan "malvado" como el mito común hace creer a la gente.