2009-06-02 13 views
7

Quindi ho un codice C++ per i nodi back-tracking in un algoritmo BFS. Sembra un po 'come questo:I loop infiniti sono in cattiva forma?

typedef std::map<int> MapType; 
bool IsValuePresent(const MapType& myMap, int beginVal, int searchVal) 
{ 
    int current_val = beginVal; 
    while (true) 
    { 
     if (current_val == searchVal) 
      return true; 

     MapType::iterator it = myMap.find(current_val); 
     assert(current_val != myMap.end()); 
     if (current_val == it->second) // end of the line 
      return false; 
     current_val = it->second; 
    } 
} 

Tuttavia, il while (true) sembra ... sospetto a me. So che questo codice funziona e logicamente so che dovrebbe funzionare. Tuttavia, non riesco a scuotere la sensazione che ci dovrebbe essere qualche condizione nel while, ma in realtà l'unico possibile è utilizzare una variabile bool solo per dire se è fatto. Dovrei smettere di preoccuparmi? O è davvero una brutta forma.

EDIT: Grazie a tutti per aver notato che c'è un modo per aggirare questo. Tuttavia, mi piacerebbe comunque sapere se ci sono altri casi validi.

+0

Questo è stato anche discusso un po' qui. http://stackoverflow.com/questions/885908/ – Copas

+0

Non so. I loop infiniti sono in cattive condizioni? –

risposta

22

Credo che ci siano casi in cui va bene che esistano cicli apparentemente infiniti. Tuttavia questo non sembra essere uno di loro. Sembra che si potrebbe altrettanto facilmente scrivere il codice come segue

while (current_val != searchVal) { 
    MapType::iterator it = myMap.find(current_val); 
    assert(current_val != myMap.end()); 
    if (current_val == it->second) // end of the line 
     return false; 
    current_val = it->second 
} 
return true; 

Questo sembra esprimere il vero intento del ciclo migliore

+5

+1 Per una più chiara espressione di intento e funzione. –

+0

potresti ancora migliorare inizializzando current_val su map.begin() e aggiungilo a while while (... && current_val! = It-> second) e forse anche convertendo in do-mentre – stefanB

+0

concordato. Questo è più facile da leggere e meno incline agli errori di conseguenza. Un altro pensiero con loop infiniti - a volte non è una cattiva idea progettare una sorta di fuga nel codice se può essere incline a comportamenti veramente "infiniti". Questo può essere sotto forma di controllo per l'input dell'utente (user hit escape), o in altre situazioni che si fermano dopo un timeout predefinito. –

0

Beh, un commento che dice che in realtà non è un ciclo infinito aiuterebbe:

while (true) // Not really an infinite loop! Guaranteed to return. 

Sono d'accordo che si dovrebbe avere una condizione, ma questo è bene in alcune situazioni (e non è sempre possibile o facile da fare una condizione).

+0

Se i riferimenti in qualche modo ottengono un riferimento vagante a qualcosa vicino all'inizio della catena, allora si collegheranno all'infinito. Questo è vero sia per la versione 'loop infinito', sia per la versione creata da JaredPar. Tuttavia, la sua versione mostra effettivamente i loop intesi nel condizionale in cui il tuo non fa – DevinB

+0

Sì! I commenti risolvono sempre questo problema. –

+0

Questo è un commento piuttosto inutile. Non dice in quali condizioni ritorna, niente. Un buon commento potrebbe essere che ritorna sotto una serie specifica di condizioni che sono troppo complicate per essere concisamente inserite all'interno di questa coppia di parentesi, quindi elencare le condizioni. Naturalmente, se dovessi commentare in modo chiaro, potresti anche CODICE che chiaramente nel primo caso (che di solito è il caso) –

6

ci sono momenti e luoghi per un loop infinito - non sono convinto questo è uno di loro. D'altra parte, non è affatto un problema eclatante qui.

while (currentVal != searchVal) 
{ 
    ... 
} 
return true; 

Un posto di usarli è quando il processo è veramente a tempo indeterminato - un processo demone con un ciclo monitor che non terminerà.

+0

E se volessi far smettere il demone? –

+0

Sono disponibili varie opzioni: interrompere il ciclo altrimenti indefinito o chiamare una funzione simile a una uscita che non ritorna. Entrambi sono efficaci. –

+0

Suppongo che dovrei dire "o interrompere (o restituire) da ..." –

5

ci sono situazioni in cui un costrutto come questo ha un senso:

  1. La condizione di interruzione viene calcolato all'interno del ciclo
  2. Ci sono condizioni più rottura e sono tutti ugualmente importanti
  3. si vuole veramente un loop infinito;) ..
0

Smettere di preoccuparsi. Questa non è una cattiva forma se aiuta a semplificare la logica del codice e migliora la manutenibilità e la leggibilità. Vale la pena, tuttavia, di documentare i commenti sulle condizioni di uscita previste e sul perché l'algoritmo non scivoli in un ciclo infinito.

+0

Come ha mostrato JaredPar, in realtà non semplifica la logica. Come ho detto, però, documentarlo è sicuramente una buona idea. – Zifre

0

Beh, sì , ma le due pagine di codice da scrivere se non si desidera che il ciclo principale di essere qualcosa di simile a while(true) è ancora peggio modulo.

1

Anche se li ho già fatto, voterei sempre cercando la soluzione più chiara usando qualcosa di leggibile, che generalmente includerebbe un'espressione valida nel ciclo while - altrimenti si sta scandendo il codice in cerca la pausa.

Non sono davvero terrorizzato da loro o niente, ma so che alcune persone lo sono.

13

I miei due centesimi sono: il codice deve essere self-documenting. Cioè, quando mi viene dato un pezzo di codice, preferirei guardare e dire all'intento del programmatore di leggere i commenti o arrancare nel codice circostante. Quando ho letto:

while(true) 

Questo mi dice che il programmatore voleva un ciclo infinito; che la condizione di fine non può essere specificata. Questo è l'intento dei programmatori in alcune circostanze; un loop del server, per esempio, e questo è il momento in cui dovrebbe essere usato.

Nel codice precedente, il ciclo non è destinata ad essere sempre, ha una condizione di fine chiara, e per essere semanticamente chiaro, come altri hanno sottolineato:

while (currentVal != searchVal) 

opere, così il tempo (vero) è chiaramente inferiore e dovrebbe essere evitato in questo caso.

4

while(true) viene utilizzato nei giochi per il ciclo di gioco principale: i giochi leggono continuamente l'input del lettore, elaborano le interazioni tra gli oggetti e dipingono lo schermo, quindi ripetono. Questo ciclo continua all'infinito finché qualche altra azione non si interrompe da quel ciclo (abbandonando il gioco, finendo il livello).

Ho cercato di trovare rapidamente questo loop principale nel codice sorgente di Quake 1, ma c'erano almeno 50 occorrenze di "while(1)", così come alcune scritte come "for(;;)", e non ero immediatamente sicuro quale era il ciclo di gioco principale.

+0

Mi chiedo se questo sia davvero un buon esempio del perché NON usare mentre (vero) ... Voglio dire, se lo si utilizza solo nei casi che non ritornano, si saprebbe quale era il ciclo di gioco. Meglio ancora, se dicesse quello mentre (correndo), sapresti qual è il vero loop e comunicherai al programmatore esattamente come ti aspetti di essere fermato (altrimenti è un break? Return? Exit? quale sarà la causa della corretta procedura di spegnimento?) –

+0

La maggior parte dei loop di gioco che ho visto o scritto sono più come 'while (! Exiting) {...}' – Zifre

+0

'while (in esecuzione)' sarebbe probabilmente stato visto come uno spreco di cicli della CPU - il controllo della variabile 'running' perderebbe un ciclo o due, e ancora di più sarebbe sprecato in attesa che venga letto dalla RAM. –

5

Sono d'accordo con le altre risposte che in questo caso non è necessario un ciclo infinito.

Tuttavia, un altro punto potrebbe essere che quando si do ha un ciclo infinito, for(;;) potrebbe essere un modo migliore per esprimerlo. Alcuni compilatori generano avvisi per while(true) (la condizione viene sempre valutata come falsa) e l'intenzione è meno chiara perché sembra un qualsiasi altro ciclo. Forse era solito dire while (x == true) e hai rimosso accidentalmente lo x invece dello true. for(;;) dice chiaramente che questo è destinato ad essere un ciclo infinito. O forse hai intenzione di scrivere qualcosa come while(t), ma Intellisense nel tuo IDE è stato avviato e ha deciso di completare automaticamente a true.

for(;;) d'altra parte, non è qualcosa che potresti mai digitare accidentalmente. (Ed è più facile da cercare. While (true) potrebbe anche essere scritto come, mentre (1))

Né versioni sbagliato, ma for(;;) potrebbe essere più intuitiva perché non v'è alcuna condizione del ciclo.

+0

+1 per spiegare la differenza tra 'for (;;)' e 'while (true)' – pierrotlefou

0

Non è raro trovare un loop infinito nel codice dei sistemi embedded - spesso circonda macchine a stati finiti, il controllo di chip e dispositivi periferici, ecc

0

amo loop infinito come la struttura di controllo al di fuori di una macchina a stati finiti. E 'effettivamente un goto strutturato:

}

+0

Questo dovrebbe ancora andare come 'while ((int c = ReadInput())! = EOF) {..}' – Erbureth

+0

Quale forza c fuori dal perimetro del ciclo o non è possibile distinguere tra EOF e errore. I costrutti di loop stucche non sono sempre tuoi amici. – plinth

Problemi correlati