2009-08-11 4 views
9

Ho un programma in cui ho bisogno di uscire da un gran numero di loop nidificati. Finora, il modo in cui molte persone mi hanno detto di farlo è usare un brutto goto nel mio codice.L'utilizzo di goto causerà perdite di memoria?

Ora, se creo un gruppo di stack locali (penso che sia quello che vengono chiamati, se non lo sono, intendo solo variabili regolari senza usare il nuovo comando) le variabili all'interno dei miei loop e il mio programma lo colpisce se si dice che fa scattare il goto, incontrerò una perdita di memoria a causa del mio programma che ha interrotto molti loop in modo improprio e non sta pulendo le variabili locali?

+0

Non ti perdere la memoria con quelle auto (ciò che si chiamati stack). Ma per favore NON USARE GOTO. –

+8

Cosa c'è di sbagliato in GOTO? –

+0

Domanda correlata: http://stackoverflow.com/questions/1257744 –

risposta

19

No, non sarà causare una perdita di memoria . L'utilizzo di goto non "interrompe i loop in modo errato". È solo il generalmente non consigliato da un punto di vista della struttura del codice.

A parte questo, quando si lascia il ciclo, le variabili locali usciranno dall'ambito e saranno estratte dallo stack (cioè ripulite) nel processo.

+0

Ah, ci siamo, grazie. – Faken

+0

Per uscire da un ciclo in anticipo è possibile: (a) utilizzare un goto con un'etichetta. (b) utilizzare un oggetto di ciclo aggiuntivo, dichiarato prima dei loop e controllato nell'istruzione condizionale di ogni ciclo. (c) simile a 'b' ma controllare lo stato dell'oggetto oggetto "pausa" se necessario. Infine (d) dividi la funzione in due e usi un ritorno per saltare fuori dal ciclo. IMHO, solo uno di questi evidenzia chiaramente l'intento dell'autore del codice. Un ulteriore vantaggio è che goto rende banale la ricerca di queste rare situazioni e quindi possono essere facilmente rivedute. –

0

No, non lo farai.

Tuttavia, assicurarsi che tutte le risorse esterne siano correttamente rilasciate. Ad esempio, se hai aperto un file, sarebbe possibile saltare oltre il punto in cui verrebbe normalmente chiuso.

0

No. Le variabili locali non devono essere pulite singolarmente. Quando la pila si apre, tutte le variabili locali andranno via insieme ad essa.

2

No. È possibile solo perdita di memoria allocata dinamicamente.

+1

È possibile perdere memoria in altri modi. Assegna qualche dozzina di megabyte su una pila di thread, quindi vai a dormire per un po ', ad esempio :) – bdonlan

+2

lol allora dovresti essere sparato – hobodave

+0

+1, hobodave. Tu, signore, sei il primo a farmi fottere oggi. – jkeys

1

Le variabili di stack sono definite (e allocate) nel momento in cui si immette la funzione e vengono eliminate implicitamente nel momento in cui si esce dalla funzione (poiché l'intero record di stack di chiamate viene interrotto). Nessuna quantità di rimbalzi all'interno della funzione può causare un disastro con la memoria che è stata allocata per tutto il tempo. Indipendentemente dal percorso di esecuzione che si esegue attraverso il codice, il record dello stack verrà visualizzato quando il controllo ritorna alla funzione di chiamata e la memoria verrà liberata.

+0

Sì, ma cosa succede se non sto usando una funzione? È anche vero se uso goto per uscire da molti loop contemporaneamente nel mio programma principale? – Faken

+0

Tutto è all'interno di una funzione, anche se quella funzione è main(). Il record di stack per main() viene assegnato all'avvio del programma e rilasciato al termine del programma, le stesse regole di qualsiasi altra funzione. – VoteyDisciple

+0

In C++ e C il codice è sempre in esecuzione in una funzione o in un'altra. Questa funzione potrebbe essere main(), ovviamente. –

1

Goto non è sempre male, ma nel tuo caso probabilmente non dovresti usare goto.

Vedere esempi di buon utilizzo di goto here e here.

Se si goto un'etichetta esterna all'ambito, il proprio oggetto in pila verrà liberato.

Esempio:

#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; 
} 

Questo stamperà:

All'interno portata
un distruttore
Dopo l etichetta

+0

Hai ragione, certo, ma la tempestività della chiamata di distruzione non viene mostrata da questo output. Forse aggiungere cout intorno all'etichetta 'l'? – xtofl

+0

@xtofl: buona idea, ho aggiunto qualche altro cout per chiarire –

0

No, eventuali variabili automatiche nei loop non causeranno perdite di programmazione se si interrompono i loop con un'istruzione goto.

1

Le altre risposte sono vere .... tuttavia, se si devono annidare i loop in modo diverso, metterei in dubbio il design che li ha inseriti. Suddividere quella logica in funzioni separate sarebbe un modo migliore per risolvere un problema del genere.

Billy3

+0

Sì, mi interrogo sulla logica anche nell'uso di un array 5D, ma ciò che funziona, funziona. Non lo so, l'intero programma inizia come un loop gigante per cominciare e continua a fare un ciclo intero facendo un sacco di cose su una serie di dati. – Faken

+0

Holy ... a ** 5D ** array? L'unica giustificazione che ho mai avuto per questo è in PHP, dove array e oggetti potrebbero essere la stessa cosa per scopi di archiviazione dei dati ... Seriamente, a cosa serve un array 5D in C? –

+0

Quindi come straniero dargli il benvenuto. Ci sono più cose in cielo e in terra, Orazio, di quante ne sogni la tua filosofia. –

5

variabili di stack (autos, non autobots) non sono "perde" come le variabili assegnate tramite new() o malloc().

Per quanto riguarda il "brutto" del gotos che è solo dogmatico. Leggendo Knuth, era geniale come Dijkstra. http://pplab.snu.ac.kr/courses/adv_pl05/papers/p261-knuth.pdf Evitare la programmazione basata sulla pasta, ma l'uso attento non si degrada in spaghetti.

Dijkstra non gli piacevano PERCHÉ la maggior parte di quello che si può fare con gotos può essere fatto con altre tecniche di programmazione strutturate e usa meno codice, rendendo l'altro strutturato meno incline agli errori.

Capire che il gotos non dovrebbe essere la tua prima soluzione, e non fare il possibile per usarli, ma se ha senso non sottomettersi ai dogmatic lench mobs. L'affermazione break è solo un goto sotto mentite spoglie concepito per casi in cui la rigida osservanza del comandamento "Non usare gotos" non aveva senso.

+1

Dijkstra non gli piacevano perché l'uso abituale di tutti si stava dimostrando un ostacolo all'adozione della programmazione strutturata. break non è "goto in incognito" più di altri o mentre "goto travestito". Sono tutti costrutti di programmazione strutturati che portano a un trasferimento di controllo non sequenziale. –

+3

Break interrompe la critica "single exit" di cui Dijkstra era così affezionato. Ti lascia fuori dal centro di un costrutto ben strutturato come un ciclo, che ha una singola voce e una singola uscita. Una pausa deve essere usata in congiunzione con una valutazione condizionale per essere pratica. se goto era il tipo di istruzione dijstra voluto sostituire con programmazione strutturata. se l'interruzione è il costrutto identico in cui l'unica differenza è goto è stata sostituita dall'interruzione. Break è considerato solo marginalmente migliore di un goto per questi casi perché sei limitato a dove può andare la pausa. – NoMoreZealots

+0

La pausa è decisamente "migliore" di goto, proprio per la ragione che esiste solo un posto dove può andare la pausa. Tali limiti sono esattamente ciò che distingue la programmazione strutturata come innovazione. "goto in incognito" non è altro che un insulto maccartista - chiunque può trovare qualche somiglianza tra assolutamente qualsiasi controllo di flusso e "goto". Ma questo non è rilevante se la tecnica in questione fornisce una struttura per aiutare nella comprensione del codice. La terminazione del loop con interruzione fa esattamente questo. –

0

Torna a goto le risorse di perdita? O altri eventuali problemi con il codice sottostante?

rieseguire:

 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 
     { 

     }