2009-08-11 9 views
9

Ich habe ein Programm, in dem ich aus einer großen Reihe von geschachtelten For-Schleifen ausbrechen muss. Bis jetzt haben die meisten Leute mir gesagt, dass ich es tun soll, einen hässlichen Goto in meinem Code zu verwenden.Wird es zu Speicherlecks kommen?

Nun, wenn ich eine Reihe von lokalen Stack erstellen (ich denke, dass sie so genannt werden, wenn nicht, meine ich nur normale Variablen ohne den neuen Befehl) Variablen in meinen Schleifen und mein Programm trifft diese Aussage triggert den goto, werde ich auf ein Speicherleck stoßen, weil mein Programm viele Schleifen nicht ordnungsgemäß beendet und die lokalen Variablen nicht aufräumt?

+0

Sie werden nicht Speicher mit diesen Autos lecken (was Sie genannt Stack). Aber bitte benutze GOTO NICHT. –

+8

Was ist los mit GOTO? –

+0

In Verbindung stehende Frage: http://stackoverflow.com/questions/1257744 –

Antwort

19

Nein, Sie werden nicht einen Speicherverlust verursachen . Die Verwendung eines goto führt nicht dazu, dass "Schleifen nicht ordnungsgemäß beendet werden". Es ist nur nicht allgemein von einem Code-Struktur-Point-of-View empfohlen.

Abgesehen davon, wenn Sie die Schleife verlassen, werden die lokalen Variablen außerhalb des Geltungsbereichs und von den Stapel (d. H. Aufgeräumt) in den Prozess.

+0

Ahh da gehen wir, danke. – Faken

+0

Um eine Schleife vorzeitig zu beenden, können Sie: (a) ein Goto mit einem Label verwenden. (b) Verwenden eines zusätzlichen Schleifenbedingungsobjekts, das vor den Schleifen deklariert wird und in der Bedingungsanweisung jeder Schleife eingecheckt wird. (c) ähnlich wie "b", aber prüfen Sie ggf. den Status des Bedingungsobjekts "break". Schließlich (d) teilen Sie die Funktion in zwei Teile auf und verwenden eine Rückkehr, um aus der Schleife herauszuspringen. IMHO, nur einer von diesen unterstreicht deutlich die Absicht des Autors des Codes. Ein weiterer Vorteil ist, dass es bei goto die Suche nach diesen seltenen Situationen trivial macht, sodass sie leicht begutachtet werden können. –

0

Nein, werden Sie nicht.

Stellen Sie jedoch sicher, dass alle externen Ressourcen ordnungsgemäß freigegeben sind. Wenn Sie beispielsweise eine Datei öffnen, können Sie an der Stelle vorbeispringen, an der sie normalerweise geschlossen wäre.

0

Nein. Lokale Variablen müssen nicht einzeln bereinigt werden. Wenn der Stapel auftaucht, werden alle lokalen Variablen mit ihm verschwinden.

2

Nein. Sie können nur Speicher verlieren, der dynamisch zugewiesen wird.

+1

Sie können Speicher auf andere Arten verlieren. Verteilen Sie ein paar Dutzend Megabyte auf einem Thread-Stack, dann gehen Sie schlafen für eine Weile, zum Beispiel :) – bdonlan

+2

lol dann sollten Sie erschossen werden – hobodave

+0

+1, hobodave. Sie, Sir, sind die ersten, die mich heute zum Cracken bringen. – jkeys

1

Stack-Variablen werden in dem Moment definiert (und zugeordnet), in dem Sie die Funktion eingeben, und werden implizit eliminiert, sobald Sie die Funktion verlassen (da der gesamte Call-Stack-Datensatz entfernt wird). Kein Aufprallen innerhalb der Funktion kann möglicherweise Chaos mit Speicher verursachen, der die ganze Zeit zugewiesen wurde. Unabhängig davon, welchen Ausführungspfad Sie durch den Code verwenden, wird der Stack-Datensatz angezeigt, wenn die Steuerung zur aufrufenden Funktion zurückkehrt und der Speicher freigegeben wird.

+0

Ja, aber was passiert wenn ich keine Funktion verwende? Trifft das auch zu, wenn ich in meinem Hauptprogramm gleichzeitig viele Loops ausbrechen lasse? – Faken

+0

Alles ist innerhalb einer Funktion, auch wenn diese Funktion main() ist. Der Stack-Record für main() wird beim Start des Programms zugewiesen und beim Beenden des Programms gelöscht - dieselben Regeln wie für jede andere Funktion. – VoteyDisciple

+0

In C++ und C läuft Ihr Code immer innerhalb der einen oder anderen Funktion. Diese Funktion kann natürlich main() sein. –

1

Goto ist nicht immer schlecht, aber in Ihrem Fall sollten Sie wahrscheinlich nicht goto verwenden.

Siehe Beispiele für eine gute Verwendung von goto here und here.

Wenn Sie eine Beschriftung außerhalb des Bereichs finden, wird Ihr Objekt auf dem Stapel freigegeben.

Beispiel:

#include <iostream> 
using namespace std; 

class A 
{ 
public: 
    ~A() 
    { 
    cout<<"A destructor"<<endl; 
    } 
}; 



int main(int argc, char**argv) 
{ 
    { 
    A a; 
    cout<<"Inside scope"<<endl; 
    goto l; 
    cout<<"After l goto"<<endl; 
    } 

    cout<<"Outside of scope before l label"<<endl; 

l: 
    cout<<"After l label"<<endl; 
    return 0; 
} 

Dies drucken:

Innenumfang
A destructor
Nach l Label

+0

Sie haben natürlich recht, aber die Aktualität des Destruktionsaufrufs wird von dieser Ausgabe nicht angezeigt. Fügen Sie vielleicht Couts um das Label 'l' hinzu? – xtofl

+0

@xtofl: Gute Idee, ich habe ein paar mehr Couts hinzugefügt, um zu klären –

0

Nein, automatische Variablen in Ihren Schleifen führen nicht zu Programmierverlusten, wenn Sie mit einer goto-Anweisung aus Ihren Schleifen ausbrechen.

1

Die anderen Antworten sind wahr .... aber, wenn Sie Loops anders verschachteln müssen, würde ich das Design in Frage stellen, das sie dorthin brachte. Diese Logik in separate Funktionen aufzuteilen wäre ein besserer Weg, um ein solches Problem zu lösen.

billy3

+0

Ja, ich stelle meine Logik in Frage, wenn ich ein 5D Array verwende, aber was funktioniert, funktioniert. Ich weiß nicht, das gesamte Programm beginnt als eine riesige Schleife zu beginnen, und es macht einfach Looping macht eine ganze Reihe von Sachen auf eine Reihe von Daten. – Faken

+0

Heilige ... ein ** 5D ** Array? Die einzige Rechtfertigung, die ich jemals dafür hatte, ist in PHP, wo Arrays und Objekte genauso für die Datenspeicherung geeignet sind ... Im Ernst, wofür brauchst du ein 5D-Array in C? –

+0

Deshalb als Fremden geben Sie es willkommen. Es gibt mehr Dinge in Himmel und Erde, Horatio, als in deiner Philosophie geträumt wird. –

5

Stack-Variablen (Autos, nicht autobots) sind nicht "leaky" wie Variablen über neue zugewiesen() oder malloc().

Soweit die "Hässlichkeit" von Goto ist das nur dogmatisch. Lies Knuth, er war genauso brillant wie Dijkstra. http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf Vermeiden Sie Programmierung auf Pasta-Basis, aber sorgfältiger Gebrauch wird nicht zu Spaghetti.

Dijkstra mochte sie nicht, WEIL das meiste von dem, was man mit gotos machen kann, mit anderen strukturierten Programmiertechniken gemacht werden kann und weniger Code verwendet, wodurch die andere Struktur weniger fehleranfällig wird.

Verstehen Sie, dass gotos nicht Ihre erste Lösung sein sollte, und gehen Sie nicht aus dem Weg, sie zu benutzen, aber wenn es Sinn macht, unterwerfen Sie sich nicht dogmatischen Leng Mobs. Die break-Anweisung ist ein getto getto für Fälle, in denen striktes Anhalten an das Gebot "Du sollst nicht gotos verwenden" keinen Sinn ergab.

+1

Dijkstra mochte sie nicht, weil jeder gewohnheitsmäßige Gebrauch von ihnen eine Barriere für die Einführung strukturierter Programmierung darstellte. Pause ist nicht "in der Verkleidung" mehr als sonst oder während "in Verkleidung verkleiden". Sie sind alle strukturierte Programmierkonstrukte, die zu einer nicht sequentiellen Übertragung der Kontrolle führen. –

+3

Break bricht das "Single Exit" -Kriterium, das Dijkstra so sehr liebte. Es entfernt Sie aus der Mitte eines gut strukturierten Konstrukts wie einer Schleife, die einen einzelnen Eingang und einen einzelnen Ausgang hat. Eine Unterbrechung muss in Verbindung mit einer bedingten Bewertung verwendet werden, um praktisch zu sein. wenn goto war die Art der Anweisung dijstra wollte durch strukturierte Programmierung ersetzen. Wenn Pause ist das identische Konstrukt, wo der einzige Unterschied ist, wurde durch Pause ersetzt. Break ist nur geringfügig besser als ein Goto für diese Fälle, weil Sie begrenzt sind, wo die Pause gehen kann. – NoMoreZealots

+0

Pause ist wesentlich "besser" als goto, denn genau deshalb gibt es nur einen Ort, wo die Pause gehen kann. Solche Einschränkungen zeichnen gerade die strukturierte Programmierung als Innovation aus. "In Verkleidung" ist nicht mehr als ein McCarthy-Bogen - jeder kann eine Ähnlichkeit zwischen absolut jeder Flusskontrolle und "Goto" finden. Aber das ist kaum relevant für die Frage, ob die fragliche Technik eine Struktur zur Unterstützung des Code-Verständnisses bietet. Loop-Beendigung mit Pause macht genau das. –

0

Wird rückwärts zu Leckressourcen gehen? Oder irgendwelche anderen möglichen Probleme mit unterem Code?

erneut auszuführen:

 try 
     { 
      //Setup request 
      HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 

      .... 

      //Get Response 
      HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 

      if(response != HttpStatus.OK && noOfRetries < 3) 
      { 
       noOfRetries++; 
       Thread.Sleep(10 * 1000); 


       response.Close(); 
       goto Reexecute; 
      } 
      ... 

      response.Close(); 
     } 
     catch 
     { 

     }