Aviso: Esta resposta refere-se a C ++ única ; as regras são bastante diferentes em C.
Não vai x
vazar?
Não, absolutamente não.
É um mito que goto
é alguma construção de baixo nível que permite que você substitua os mecanismos de escopo embutidos do C ++. (Se houver alguma coisa, é longjmp
que pode estar sujeito a isso.)
Considere a seguinte mecânica que evita que você faça "coisas ruins" com rótulos (o que inclui case
rótulos).
1. Escopo do rótulo
Você não pode saltar entre as funções:
void f() {
int x = 0;
goto lol;
}
int main() {
f();
lol:
return 0;
}
// error: label 'lol' used but not defined
[n3290: 6.1/1]:
[..] O escopo de um rótulo é a função na qual ele aparece. [..]
2. Inicialização do objeto
Você não pode pular na inicialização do objeto:
int main() {
goto lol;
int x = 0;
lol:
return 0;
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘int x’
Se você voltar para a inicialização do objeto, a "instância" anterior do objeto será destruída :
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]:
[..] A transferência de um loop, de um bloco ou de volta após uma variável inicializada com duração de armazenamento automático envolve a destruição de objetos com duração de armazenamento automático que estão no escopo no ponto transferido, mas não no ponto transferido para . [..]
Você não pode saltar para o escopo de um objeto, mesmo que não seja explicitamente inicializado:
int main() {
goto lol;
{
std::string x;
lol:
x = "";
}
}
// error: jump to label ‘lol’
// error: from here
// error: crosses initialization of ‘std::string x’
... exceto para certos tipos de objetos , que a linguagem pode manipular independentemente porque eles não requerem uma construção "complexa":
int main() {
goto lol;
{
int x;
lol:
x = 0;
}
}
// OK
[n3290: 6.7/3]:
É possível transferir para um bloco, mas não de uma forma que ignore as declarações com a inicialização. Um programa que salta de um ponto onde uma variável com duração de armazenamento automático não está no escopo para um ponto onde está no escopo é malformado, a menos que a variável tenha tipo escalar, tipo de classe com um construtor padrão trivial e um destruidor trivial, um Versão qualificada de cv de um desses tipos ou uma matriz de um dos tipos anteriores e é declarada sem um inicializador. [..]
3. O salto obedece ao escopo de outros objetos
Da mesma forma, objetos com duração de armazenamento automático não são "vazados" quando você está fora de seu escopogoto
:
struct T {
T() { cout << "*T"; }
~T() { cout << "~T"; }
};
int main() {
{
T t;
goto lol;
}
lol:
return 0;
}
// *T~T
[n3290: 6.6/2]:
Ao sair de um escopo (embora realizado), os objetos com duração de armazenamento automático (3.7.3) que foram construídos naquele escopo são destruídos na ordem inversa de sua construção. [..]
Conclusão
Os mecanismos acima garantem que goto
você não quebra o idioma.
Claro, isso não significa automaticamente que você "deveria" uso goto
para qualquer problema, mas não significa que ele não é tão "mal", como as ligações mito comum que as pessoas acreditam.