ti-enxame.com

Usar o goto vale a pena?

goto é quase universalmente desencorajado. Vale a pena usar esta declaração?

30
Casebash

Isso foi discutido várias vezes no Stack Overflow e Chris Gillum resumiu os possíveis usos de goto :

Sair de uma função corretamente

Geralmente, em uma função, você pode alocar recursos e precisar sair em vários locais. Os programadores podem simplificar seu código colocando o código de limpeza de recurso no final da função, todos os "pontos de saída" da função iriam para o rótulo de limpeza. Dessa forma, você não precisa escrever um código de limpeza em todos os "pontos de saída" da função.

Saindo de loops aninhados

Se você estiver em um loop aninhado e precisar interromper os loops todos, um goto pode tornar isso muito mais limpo e mais simples do que as instruções break e if-checks.

Melhorias de baixo nível de desempenho

Isso é válido apenas no código perf-critical, mas as instruções goto são executadas muito rapidamente e podem dar um impulso ao se mover através de uma função. Essa é uma faca de dois gumes, no entanto, porque um compilador normalmente não pode otimizar código que contém gotos.

Eu argumentaria, como muitos outros argumentariam, que em todos esses casos, o uso de goto é usado como um meio de sair de um canto em que um codificado foi e geralmente é um sintoma de código isso poderia ser refatorado.

51
user8

As construções de fluxo de controle de nível superior tendem a corresponder aos conceitos no domínio do problema. Um if/else é uma decisão baseada em alguma condição. Um loop diz para executar alguma ação repetidamente. Até uma declaração de pausa diz "estávamos fazendo isso repetidamente, mas agora precisamos parar".

Uma declaração goto, por outro lado, tende a corresponder a um conceito no programa em execução, não no domínio do problema. Ele diz para continuar a execução em um ponto especificado no programa . Alguém que lê o código deve inferir o que isso significa em relação ao domínio do problema.

É claro que todas as construções de nível superior podem ser definidas em termos de gotos e ramificações condicionais simples. Isso não significa que eles são apenas gotos disfarçados. Pense neles como restrito gotos - e são as restrições que os tornam úteis. Uma declaração de interrupção é implementada como um salto para o final do loop fechado, mas é melhor pensar em operar no loop como um todo.

Sendo tudo igual, o código cuja estrutura reflete a do domínio do problema tende a ser mais fácil de ler e manter.

Não há casos em que uma declaração goto seja absolutamente necessária (há m teorema nesse sentido), mas há casos em que pode ser a solução menos ruim. Esses casos variam de idioma para idioma, dependendo das construções de nível superior que o idioma suporta.

Em C, por exemplo, acredito que há três cenários básicos em que um goto é apropriado.

  1. Rompendo um loop aninhado. Isso seria desnecessário se o idioma tivesse uma declaração de interrupção rotulada.
  2. Retirada de um trecho de código (normalmente um corpo de função) em caso de erro ou outro evento inesperado. Isso seria desnecessário se o idioma tivesse exceções.
  3. Implementando uma máquina de estado finito explícita. Nesse caso (e, creio, apenas neste caso), um goto corresponde diretamente a um conceito no domínio do problema, passando de um estado para outro especificado, onde o estado atual é representado pelo bloco de código em execução no momento .

Por outro lado, uma máquina explícita de estados finitos também pode ser implementada com uma instrução switch dentro de um loop. Isso tem a vantagem de que todo estado inicia no mesmo local no código, o que pode ser útil para depuração, por exemplo.

O principal uso de um goto em uma linguagem razoavelmente moderna (que suporta if/else e loops) é simular uma construção de fluxo de controle que está faltando na linguagem.

46
Keith Thompson

Certamente depende da linguagem de programação. A principal razão pela qual goto tem sido controversa é por causa de seus efeitos nocivos que surgem quando o compilador permite que você o use com muita liberalidade. Podem surgir problemas, por exemplo, se ele permitir que você use goto de forma que agora você possa acessar uma variável não inicializada, ou pior, para pular para outro método e mexer com a pilha de chamadas. Deve ser responsabilidade do compilador proibir o fluxo de controle sem sentido.

Java tentou "resolver" esse problema, proibindo goto completamente. No entanto, Java permite que você use return dentro de um bloco finally e, portanto, faça com que uma exceção seja inadvertidamente engolida. O mesmo problema ainda está lá: o compilador é Não foi possível remover goto do idioma.

Em C #, goto é tão seguro quanto break, continue, try/catch/finally e return. Ele não permite que você use variáveis ​​não inicializadas, nem pula de um bloco finalmente etc. O compilador irá reclamar. Isso ocorre porque resolve o problema real, que é como eu disse no fluxo de controle sem sentido. goto não cancela magicamente a análise de atribuição definida e outras verificações razoáveis ​​do compilador.

11
Timwi

Sim. Quando seus loops estão aninhados em vários níveis, goto é a maneira única de romper elegantemente um loop interno. A outra opção é definir um sinalizador e interromper cada loop se esse sinalizador satisfizer uma condição. Isso é realmente feio e propenso a erros. Nesses casos, goto é simplesmente melhor.

Obviamente, a instrução break do Java faz a mesma coisa, mas sem permitir que você pule para um ponto arbitrário no código, que resolve o problema perfeitamente, sem permitir que as coisas que tornam goto mal.

9
Chinmay Kanchi

A maior parte do desânimo vem de uma espécie de "religião" criada em meio a Deus Djikstra, que foi convincente no início dos anos 60 sobre seu poder indiscriminado de:

  • pule em qualquer lugar em qualquer bloco de código
    • função não executada desde o início
    • loops não executados desde o início
    • inicialização de variável ignorada
  • afaste-se de qualquer bloco de código sem qualquer limpeza possível.

Isso não tem mais nada a ver com a instrução goto das linguagens modernas, cuja existência se deve apenas ao suporte à criação de estruturas de código diferentes das fornecidas pela linguagem.

Em particular, o primeiro ponto principal acima é mais permitido e o segundo é limpo (se você goto fora de um bloco, a pilha é desenrolada adequadamente e todos os destruidores adequados são chamados)

Você pode consultar esta resposta para ter uma idéia de como mesmo o código que não usa goto pode ser ilegível. O problema não é ir sozinho, mas o mau uso dele.

Eu posso escrever um programa inteiro sem usar if, apenas for. Obviamente, não será bem legível, uma aparência desajeitada e desnecessariamente complicada.

Mas o problema não é for. Sou eu.

Coisas como break, continue, throw, bool needed=true; while(needed) {...}, etc. estão notando mais do que mascarada goto para fugir das cimitarras dos fanáticos djikstrarianos, que - 50 anos após a invenção das línguas modernas - ainda querem seus prisioneiros. Eles esqueceram o que Djikstra estava falando, lembram-se apenas do título de sua nota (GOTO considerado prejudicial, e nem era o título dele: foi alterado pelo editor) e culpam e criticam, criticam e culpam todos os contratados que têm essas notas. carta colocada em sequência.

Chegou o ano de 2011: chegou a hora de entender que goto tem que lidar com a declaração GOTO que Djikstra estava convencendo.

7
Emilio Garavaglia

O goto estranho aqui ou ali, desde que seja local para uma função, raramente prejudica significativamente a legibilidade. Muitas vezes, é benéfico chamando a atenção para o fato de que há algo incomum nesse código que requer o uso de uma estrutura de controle um tanto incomum.

Se os gotos (locais) estão prejudicando significativamente a legibilidade, geralmente é um sinal de que a função que contém o goto se tornou muito complexa.

O último passo que eu coloquei em um pedaço de código C foi construir um par de loops interligados. Não se encaixa na definição normal de uso "aceitável" do goto, mas a função acabou sendo significativamente menor e mais clara como resultado. Para evitar o goto, seria necessária uma violação particularmente desordenada do DRY.

4
blucz

Eu acho que essa questão toda foi um caso de latir na árvore errada.

GOTO, como tal, não me parece problemático, mas muitas vezes é um sintoma de um pecado real: código de espaguete.

Se o GOTO causar um grande cruzamento das linhas de controle de fluxo, está ruim, ponto final. Se não cruzar nenhuma linha de controle de fluxo, é inofensivo. Na zona cinza no meio, temos coisas como salvamentos em loop, ainda existem alguns idiomas que não adicionaram construções que cobrem todos os casos cinza legítimos.

O único caso em que eu realmente o usei em muitos anos é o caso do loop em que o ponto de decisão está no meio do loop. Você fica com código duplicado, uma bandeira ou um GOTO. Acho a solução GOTO a melhor das três. Não há cruzamento de linhas de controle de fluxo aqui, é inofensivo.

3
Loren Pechtel

Sim, o goto pode ser usado para beneficiar a experiência do desenvolvedor: http://adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/

No entanto, assim como qualquer ferramenta poderosa (ponteiros, herança múltipla etc.), é preciso ser disciplinado usando-a. O exemplo fornecido no link usa PHP, que restringe o uso da construção goto para a mesma função/método e desativa a capacidade de saltar para um novo bloco de controle (por exemplo, loop, instrução switch, etc.)

1
AdamJonR

Depende do idioma. Ainda é amplamente utilizado na programação Cobol, por exemplo. Também trabalhei em um dispositivo Barionet 50, cuja linguagem de programação de firmware é um dialeto básico do BASIC que, naturalmente, exige que você use Goto.

1
user16764

Eu diria que não. Se você achar necessário usar o GOTO, aposto que é necessário redesenhar o código.

0
Walter

goto pode ser útil ao portar o código do assembler herdado para C. Na primeira instância, uma conversão instrução por instrução para C, usando goto como um substituto para o assembler branch, pode permitir a transferência muito rápida.

0
Graham Borland