wake-up-neo.net

Lohnt es sich jemals, goto zu verwenden?

goto wird fast allgemein entmutigt. Lohnt es sich jemals, diese Aussage zu verwenden?

30
Casebash

Dies wurde mehrmals über Stack Overflow und Chris Gillum diskutiert fasste die möglichen Verwendungen von goto zusammen :

Funktion sauber beenden

In einer Funktion können Sie häufig Ressourcen zuweisen und müssen an mehreren Stellen beendet werden. Programmierer können ihren Code vereinfachen, indem sie den Ressourcenbereinigungscode am Ende der Funktion einfügen. Alle "Austrittspunkte" der Funktion werden auf das Bereinigungsetikett gesetzt. Auf diese Weise müssen Sie nicht an jedem "Exit-Punkt" der Funktion Bereinigungscode schreiben.

Verschachtelte Schleifen verlassen

Wenn Sie sich in einer verschachtelten Schleife befinden und aus all Schleifen ausbrechen müssen, kann ein goto dies viel sauberer und einfacher machen als break-Anweisungen und if-Checks.

Leistungsverbesserungen auf niedriger Ebene

Dies ist nur in perf-kritischem Code gültig, aber goto-Anweisungen werden sehr schnell ausgeführt und können Ihnen beim Durchlaufen einer Funktion einen Schub geben. Dies ist jedoch ein zweischneidiges Schwert, da ein Compiler normalerweise keinen Code optimieren kann, der gotos enthält.

Ich würde argumentieren, wie viele andere argumentieren würden, dass in all diesen Fällen die Verwendung von goto als Mittel verwendet wird, um aus einer Ecke herauszukommen, in die man sich selbst codiert hat, und im Allgemeinen ein Symptom für Code ist das könnte überarbeitet werden.

51
user8

Kontrollflusskonstrukte auf höherer Ebene entsprechen tendenziell Konzepten im Problembereich. Ein if/else ist eine Entscheidung, die auf einer bestimmten Bedingung basiert. Eine Schleife fordert Sie auf, eine Aktion wiederholt auszuführen. Sogar in einer Pause heißt es: "Wir haben das wiederholt gemacht, aber jetzt müssen wir aufhören.".

Eine goto-Anweisung entspricht dagegen eher einem Konzept im laufenden Programm, nicht in der Problemdomäne. Es heißt, die Ausführung an einem bestimmten Punkt im Programm fortzusetzen . Jemand, der den Code liest, muss ableiten , was dies in Bezug auf die Problemdomäne bedeutet.

Natürlich können alle übergeordneten Konstrukte in Form von Gotos und einfachen bedingten Verzweigungen definiert werden. Das bedeutet nicht, dass sie nur verkleidet sind. Stellen Sie sich diese als eingeschränkte gotos vor - und es sind die Einschränkungen, die sie nützlich machen. Eine break-Anweisung wird als Sprung zum Ende der umschließenden Schleife implementiert, aber es ist besser, sie als Ganzes für die Schleife zu betrachten.

Wenn alles andere gleich ist, ist Code, dessen Struktur die der Problemdomäne widerspiegelt, leichter zu lesen und zu warten.

Es gibt keine Fälle, in denen eine goto-Anweisung unbedingt erforderlich ist (es gibt einen Satz in diesem Sinne), aber es gibt Fälle, in denen dies die am wenigsten schlechte Lösung sein kann. Diese Fälle variieren von Sprache zu Sprache, je nachdem, welche übergeordneten Konstrukte die Sprache unterstützt.

In C zum Beispiel glaube ich, dass es drei grundlegende Szenarien gibt, in denen ein goto angemessen ist.

  1. Aus einer verschachtelten Schleife ausbrechen. Dies wäre unnötig, wenn die Sprache eine beschriftete break-Anweisung hätte.
  2. Rettung aus einem Codeabschnitt (normalerweise einem Funktionskörper) im Falle eines Fehlers oder eines anderen unerwarteten Ereignisses. Dies wäre unnötig, wenn die Sprache Ausnahmen hätte.
  3. Implementierung einer expliziten Finite-State-Maschine. In diesem Fall (und ich denke nur in diesem Fall) entspricht ein goto direkt einem Konzept in der Problemdomäne, das von einem Zustand in einen bestimmten anderen Zustand übergeht, in dem der aktuelle Zustand dargestellt wird, durch den der Codeblock gerade ausgeführt wird .

Andererseits kann eine explizite endliche Zustandsmaschine auch mit einer switch-Anweisung innerhalb einer Schleife implementiert werden. Dies hat den Vorteil, dass jeder Status an derselben Stelle im Code beginnt, was beispielsweise beim Debuggen hilfreich sein kann.

Die Hauptverwendung eines goto in einer einigermaßen modernen Sprache (eine, die if/else und Schleifen unterstützt) besteht darin, ein Kontrollflusskonstrukt zu simulieren, das in der Sprache fehlt.

46
Keith Thompson

Sicher hängt es von der Programmiersprache ab. Der Hauptgrund, warum goto umstritten war, sind die negativen Auswirkungen, die auftreten, wenn der Compiler Sie zu großzügig verwenden lässt. Probleme können beispielsweise auftreten, wenn Sie goto so verwenden können, dass Sie jetzt auf eine nicht initialisierte Variable zugreifen können, oder schlimmer noch, um in eine andere Methode zu springen und mit dem Aufrufstapel herumzuspielen. Es sollte in der Verantwortung des Compilers liegen, unsinnigen Kontrollfluss zu verbieten.

Java hat versucht, dieses Problem zu "lösen", indem goto vollständig verboten wurde. Mit Java können Sie jedoch return innerhalb eines finally -Blocks verwenden und so eine Ausnahme versehentlich verschlucken. Das gleiche Problem besteht immer noch: Der Compiler ist Das Entfernen von goto aus der Sprache hat das Problem nicht behoben.

In C # ist goto so sicher wie break, continue, try/catch/finally und return. Sie können keine nicht initialisierten Variablen verwenden, Sie können nicht aus einem finally-Block herausspringen usw. Der Compiler wird sich beschweren. Dies liegt daran, dass es das real Problem löst, was wie gesagt unsinniger Kontrollfluss ist. goto bricht die Analyse bestimmter Zuweisungen und andere vernünftige Compilerprüfungen nicht auf magische Weise ab.

11
Timwi

Ja. Wenn Ihre Schleifen mehrere Ebenen tief verschachtelt sind, ist goto die nur Methode, um elegant aus einer inneren Schleife auszubrechen. Die andere Möglichkeit besteht darin, ein Flag zu setzen und aus jeder Schleife auszubrechen, wenn dieses Flag eine Bedingung erfüllt. Das ist wirklich hässlich und ziemlich fehleranfällig. In diesen Fällen ist goto einfach besser.

Natürlich macht Javas mit break bezeichnete Anweisung dasselbe, aber ohne dass Sie zu einem beliebigen Punkt im Code springen können, wodurch das Problem sauber gelöst wird, ohne die Dinge zuzulassen, die goto böse machen.

9
Chinmay Kanchi

Der größte Teil der Entmutigung kommt von einer Art "Religion", die von Gott Djikstra geschaffen wurde, der in den frühen 60er Jahren von seiner wahllosen Macht überzeugt war:

  • springe irgendwo in einen beliebigen Codeblock
    • funktion nicht von Anfang an ausgeführt
    • schleifen nicht von Anfang an ausgeführt
    • übersprungene Variableninitialisierung
  • springen Sie von jedem Codeblock weg, ohne dass eine Bereinigung möglich ist.

Dies hat nichts mehr mit der Anweisung goto der modernen Sprachen zu tun, deren Existenz lediglich darauf zurückzuführen ist, dass andere als die von der Sprache bereitgestellten Codestrukturen erstellt werden.

Insbesondere ist der erste Hauptpunkt oben noch zulässig und der zweite wird gereinigt (wenn Sie goto aus einem Block heraus sind, wird der Stapel ordnungsgemäß abgewickelt und alle geeigneten Destruktoren aufgerufen).

Sie können auf diese Antwort verweisen, um eine Vorstellung davon zu bekommen, wie selbst Code, der goto nicht verwendet, unlesbar sein kann. Das Problem liegt nicht an sich selbst, sondern an der schlechten Verwendung.

Ich kann ein ganzes Programm schreiben, ohne if zu verwenden, nur for. Natürlich wird es nicht gut lesbar sein, ein ungeschicktes und unnötig kompliziertes Aussehen.

Das Problem ist jedoch nicht for. Da ich bin.

Dinge wie break, continue, throw, bool needed=true; while(needed) {...} usw. sind mehr als Maskerade goto um den Skimitaren der dschikstrarischen Eiferer zu entkommen, die - 50 Jahre nach der Erfindung der modernen Sprachen - immer noch ihre Gefangenen wollen. Sie vergaßen, wovon Djikstra sprach, sie erinnerten sich nur an den Titel seiner Notiz (GOTO wurde als schädlich angesehen, und es war nicht einmal sein einziger Titel: er wurde vom Herausgeber geändert) und beschuldigten und schlugen, schlugen und beschuldigten jeden Konstrukt, der diese 4 hatte Brief nacheinander platziert.

Es ist 2011: Es ist Zeit zu verstehen, dass goto nichts mit der GOTO Aussage zu tun hat, über die Djikstra überzeugt hat.

7

Das seltsame Hin und Her hier oder da beeinträchtigt die Lesbarkeit selten erheblich, solange es sich um eine lokale Funktion handelt. Dies kommt häufig zugute, indem auf die Tatsache hingewiesen wird, dass in diesem Code etwas Ungewöhnliches vor sich geht, das die Verwendung einer etwas ungewöhnlichen Kontrollstruktur erfordert.

Wenn (lokale) Gotos die Lesbarkeit erheblich beeinträchtigen, ist dies normalerweise ein Zeichen dafür, dass die Funktion, die das Goto enthält, zu komplex geworden ist.

Das letzte, was ich in einen Teil des C-Codes geschrieben habe, war das Erstellen eines Paares von ineinandergreifenden Schleifen. Es passt nicht in die normale Definition von "akzeptabel" für die Verwendung, aber die Funktion wurde dadurch deutlich kleiner und klarer. Um dies zu vermeiden, wäre eine besonders unordentliche Verletzung von DRY erforderlich gewesen.

4
blucz

Ich denke, bei diesem ganzen Problem ging es darum, den falschen Baum zu bellen.

GOTO als solches scheint mir nicht problematisch zu sein, sondern ist sehr oft ein Symptom für eine tatsächliche Sünde: Spaghetti-Code.

Wenn das GOTO eine größere Kreuzung der Flusskontrollleitungen verursacht, ist es schlecht, Punkt. Wenn es keine Flusskontrollleitungen kreuzt, ist es harmlos. In der Grauzone dazwischen gibt es Dinge wie Loop-Bailouts. Es gibt immer noch einige Sprachen, die keine Konstrukte hinzugefügt haben, die alle legitimen Graufälle abdecken.

Der einzige Fall, in dem ich es seit vielen Jahren tatsächlich benutze, ist der Fall der Schleife, bei der sich der Entscheidungspunkt in der Mitte der Schleife befindet. Sie haben entweder doppelten Code, eine Flagge oder ein GOTO. Ich finde die GOTO-Lösung die beste der drei. Hier gibt es keine Kreuzung von Durchflusskontrollleitungen, es ist harmlos.

3
Loren Pechtel

Ja, das goto kann verwendet werden, um die Erfahrung des Entwicklers zu verbessern: http://adamjonrichardson.com/2012/02/06/long-live-the-goto-statement/

Wie bei jedem leistungsstarken Tool (Zeiger, Mehrfachvererbung usw.) muss man es jedoch disziplinieren. Das in dem Link bereitgestellte Beispiel verwendet PHP, wodurch die Verwendung des goto-Konstrukts auf dieselbe Funktion/Methode beschränkt wird und die Möglichkeit deaktiviert wird, in einen neuen Steuerblock (z. B. Schleife, switch-Anweisung usw.) zu springen.

1
AdamJonR

Kommt auf die Sprache an. Es ist zum Beispiel in der Cobol-Programmierung immer noch weit verbreitet. Ich habe auch an einem Barionet 50-Gerät gearbeitet, dessen Firmware-Programmiersprache ein früher BASIC-Dialekt ist, für den Sie natürlich Goto verwenden müssen.

1
user16764

Ich würde nein sagen. Wenn Sie feststellen, dass GOTO verwendet werden muss, muss der Code wahrscheinlich neu gestaltet werden.

0
Walter

goto kann nützlich sein, wenn älterer Assembler-Code nach C portiert wird. In erster Linie eine Anweisung-für-Befehl-Konvertierung nach C, wobei goto als Ersatz für branch Anweisung kann eine sehr schnelle Portierung ermöglichen.

0
Graham Borland