2010-09-29 8 views
13

Recentemente abbiamo trovato un "buon modo" per commentare righe di codice utilizzando continuare:Un altro modo di utilizzare continuare parola chiave in C++

for(int i=0; i<MAX_NUM; i++){ 
    .... 
    .... //--> about 30 lines of code 
    continue; 
    ....//--> there is about 30 lines of code after continue 
    .... 
} 

mi gratto la testa chiedendo perché il precedente sviluppatore ha messo la parola chiave continua all'interno del ciclo intensivo. Molto probabilmente è lui/lei sente è più facile mettere una parola chiave "continua" invece di rimuovere tutto il codice indesiderato ...

Mi innescare un'altra domanda, cercando in seguito scenario:

Scenario A:

for(int i=0; i<MAX_NUM; i++){ 
    .... 
    if(bFlag) 
    continue; 
    ....//--> there is about 100 lines of code after continue 
    .... 
} 

Scenario B:

for(int i=0; i<MAX_NUM; i++){ 
    .... 
    if(!bFlag){ 
    ....//--> there is about 100 lines of code after continue 
    .... 
    } 
} 

Quale pensi sia il migliore? Perché? Che ne dici di una parola chiave break?

+21

usando continua invece di commentare il codice non necessario è male! – Francesco

+4

Ora conosci la ragione per cui è stato "elevato" a un manager. – sbi

+2

L'unico semi-beneficio a cui posso pensare per lasciare un codice inutilizzato non raggiungibile, è se è solo temporaneamente inutilizzato e vuoi assicurarti che sia ancora compilato. Ad esempio, verifica che sia aggiornato per eventuali modifiche alle firme delle funzioni che chiama. Se hai commentato, non lo sarebbe. Ma è un vantaggio molto marginale: non stai testando il codice, quindi sei solo parzialmente sicuro che funzioni ancora. Dato che dovrai testarlo quando lo riattiverai, potresti anche aggiustarlo per compilarlo. E più a lungo lo lasci in questo modo, più facilmente si romperà in modo sottile. –

risposta

23

L'utilizzo di continue in questo caso riduce notevolmente l'annidamento e spesso rende il codice più leggibile.

Ad esempio:

for(...) { 
    if(condition1) { 
     Object* pointer = getObject(); 
     if(pointer != 0) { 
      ObjectProperty* property = pointer->GetProperty(); 
      if(property != 0) { 
     ///blahblahblah... 
     } 
    } 
} 

diventa solo

for(...) { 
    if(!condition1) { 
     continue; 
    } 
    Object* pointer = getObject(); 
    if(pointer == 0) { 
     continue; 
    } 
    ObjectProperty* property = pointer->GetProperty(); 
    if(property == 0) { 
     continue; 
    } 

    ///blahblahblah... 
} 

Vedete - codice diventa lineare invece di nidificato.

È inoltre possibile trovare le risposte a this closely related question utili.

+0

nice ... Mi piace il tuo esempio sul vantaggio di usare continua. È simile a preferire un passaggio su molti if() s. –

+0

Tranne nella maggior parte dei casi, se si hanno molte istruzioni if, una tabella di ricerca dei puntatori di funzione sarebbe più chiara di un interruttore e più facile da leggere e conservare. – haylem

+0

Le linee guida per la codifica dei clang favoriscono anche lo stile "early return" per ridurre il rientro: ritorno anticipato, uso esteso di continue/break, ecc ... –

2

Pensa innanzitutto alla leggibilità, che è ciò che renderà il tuo codice più gestibile. L'utilizzo di una dichiarazione continue è chiara per l'utente: in questa condizione non c'è nient'altro che posso/voglio fare con questo elemento, dimenticarlo e provare quello successivo. D'altra parte, lo if sta solo dicendo che il prossimo blocco di codice non si applica a quelli per cui la condizione non è soddisfatta, ma se il blocco è abbastanza grande, potresti non sapere se c'è effettivamente un ulteriore codice che applicare a questo particolare elemento.

Io preferisco lo continue al di sopra se per questo particolare motivo. Più esplicitamente afferma l'intento.

+0

Bel pensiero: + 1 – Chubsdad

+0

In realtà non sono d'accordo con questo (il più delle volte). Mentre la dichiarazione continua è chiara, se presenta una rottura nel flusso del programma che rende più difficile da seguire, mentre escludendo se le istruzioni sono più facili da elaborare mentalmente. Aggiungerebbe alcuni livelli di scoping, ma come accennato da Péter Török, allora molto probabilmente vorrai estrarre la porzione di codice incriminata. – haylem

4

L'uso di "commento" di continue è offensivo come un goto :-). È così facile mettere un #if 0/#endif o /*...*/, e molti editori quindi codificheranno il codice commentato in modo che sia immediatamente evidente che non è in uso. (A volte mi piace, ad esempio, #ifdef USE_OLD_VERSION_WITH_LINEAR_SEARCH quindi so che cosa è rimasto lì, dato che mi è subito chiaro che non avrei mai avuto un nome macro così stupido se mi aspettassi che qualcuno lo definisse durante la compilazione ... suppongo che dovrei spiegarlo al team se ho condiviso il codice in quello stato però.) Altre risposte indicano che i sistemi di controllo del codice sorgente ti permettono semplicemente di rimuovere il codice commentato, e mentre questa è la mia pratica prima del commit - c'è spesso una fase di "lavoro" dove vuoi in giro per il massimo riferimento incrociato, copia-incolla ecc.

Per gli scenari: praticamente, non importa quale si utilizza a meno che il progetto abbia un approccio coerente con cui è necessario adattarsi, quindi suggerire l'utilizzo di ciò che sembra più leggibile/espressivo nelle circostanze. Nei blocchi di codice più lunghi, un singolo continua può essere meno visibile e quindi meno intuitivo, mentre un gruppo di essi - o molti sparsi nel loop - è difficile da perdere.Anche il codice troppo annidato può diventare brutto. Scegliere quindi se non si è sicuri, quindi cambiarlo se l'alternativa inizia a sembrare attraente.

comunicano informazioni leggermente diversa al lettore anche: continue significa "ehi, esclude tutte queste circostanze e poi guardare il codice qui sotto", mentre il blocco if significa che si deve "spingere" un contesto ma hanno ancora tutti nella tua mente mentre cerchi di capire il resto degli interni del ciclo (qui, solo per trovare il se immediatamente seguito dalla terminazione del ciclo, quindi tutto lo sforzo mentale è stato sprecato. Contrastando questo, le dichiarazioni continue tendono a scatenare un controllo mentale per assicurarsi che tutti i passaggi necessari siano stati completati prima dell'iterazione del ciclo successivo - che tutto sia valido come potrebbe essere qualsiasi cosa segua, e se qualcuno dice aggiunge un'ulteriore istruzione di incremento o debug nella parte inferiore del ciclo, allora devono sapere che ci sono continuare le dichiarazioni che possono anche voler gestire.

È anche possibile decidere quale utilizzare in base a quanto è banale il test, proprio come alcuni programmatori utilizzeranno le dichiarazioni di ritorno anticipato per condizioni di errore eccezionali, ma utilizzeranno una variabile "risultato" e una programmazione strutturata per i flussi previsti. Tutto può diventare complicato: la programmazione deve essere complessa almeno quanto i problemi: il tuo compito è renderlo minimamente più disordinato/più complesso di così.

Per essere produttivi, è importante ricordare "Non sudare le piccole cose", ma in IT può essere un dolore giusto imparare cos'è piccolo :-).

parte: si possono trovare utile fare un po 'di sfondo leggendo sui pro/contro di programmazione strutturata, che coinvolge i punti di entrata/uscita singoli, goto ecc ..

6

Per la vostra prima domanda, può essere un modo di saltare il codice senza commentarlo o eliminarlo. Non raccomanderei di farlo. Se non vuoi che il tuo codice sia eseguito, non precederlo con un continuo/break/return, in quanto ciò potrebbe generare confusione quando tu/altri stai revisionando il codice e potresti essere visto come un bug.

Per quanto riguarda la seconda domanda, sono fondamentalmente identiche (dipende dall'output dell'assieme) le prestazioni e dipendono molto dalla progettazione. Dipende dal modo in cui si desidera che i lettori del codice "traducano" in inglese, come accade per la maggior parte durante la lettura del codice.

Quindi, il primo esempio può essere "Do blah, blah, blah. If (espressione), continua alla successiva iterazione". Mentre il secondo può leggere "Do blah, blah, blah." (Espressione), bla bla bla "

Quindi, l'uso di una dichiarazione if può compromettere l'importanza del codice che lo segue.

A mio parere, preferirei continuare se possibile, perché ridurrebbe la nidificazione.

4

Sono d'accordo con altri rispondenti che il primo utilizzo di continue è BAD. codice non utilizzato deve essere rimosso (Se desiderate comunque in un secondo momento, si può sempre trovare dal vostro SCM -? Si utilizza uno SCM, a destra :-)

Per il secondo, alcune risposte hanno sottolineato la leggibilità, ma Mi manca una cosa importante: IMO la prima mossa dovrebbe essere quella di estrarre 100 righe di codice in uno o più metodi separati. Successivamente, il ciclo diventa molto più breve e più semplice e il flusso di esecuzione diventa evidente .Se posso estrarre il codice in un unico metodo, io personalmente preferisco un if:

for(int i=0; i<MAX_NUM; i++){ 
    .... 
    if(!bFlag){ 
    doIntricateCalculation(...); 
    } 
} 

Ma un continue sarebbe quasi ugualmente bene a me. Infatti, se ci sono più continue s/return s/break s all'interno di quelle 100 righe di codice, è impossibile estrarlo in un unico metodo, quindi il refactoring potrebbe finire con una serie di continue s e chiamate di metodi:

for(int i=0; i<MAX_NUM; i++){ 
    .... 
    if(bFlag){ 
    continue; 
    } 
    SomeClass* someObject = doIntricateCalculation(...); 
    if(!someObject){ 
    continue; 
    } 
    SomeOtherClass* otherObject = doAnotherIntricateCalculation(someObject); 
    if(!otherObject){ 
    continue; 
    } 
    // blah blah 
} 
+0

+0,5 per suggerire di rifattorizzare ed estrarre su un altro metodo e +0.5 per suggerire la clausola! BFlag sull'uso continuare. – haylem

+0

+1 per suggerire l'uso delle funzioni. Le funzioni devono essere ** brevi **, leggibili, comprensibili e con un nome chiaro. –

+0

@Stephane: funzioni come quelle proposte sono spesso chiamate solo da un posto, che il nome è breve è una priorità bassa. @ Péter: quelli if/continua sono ancora piuttosto brutti: -) ...se solo C++ permettesse più dichiarazioni variabili all'interno di un if, piuttosto che di uno solo, allora potremmo usare 'if ((SomeClass * someObject = ...) e (SomeOtherClass * otherObject = ...)) {...}' o equivalentemente 'if (! (SomeClass * someObject = ...) o! (...)) continua;'. Così com'è, può considerare delocalizzato 'SomeClass * someObject; SomeOtherClass * otherObject; 'then' if (! (SomeObject = ...) o! (OtherObject = ...)) '. Tutti i gusti –

4

Odio commentare codice inutilizzato. Quello che ho fatto è quello,

Io li rimuovo completamente e quindi il check-in nel controllo di versione.

Chi ha ancora bisogno di commentare il codice inutilizzato dopo l'invenzione del controllo del codice sorgente?

+1

Sono d'accordo con quello nella maggior parte dei casi, ma con una riserva ... Se non tenete d'occhio il vostro SCM regolarmente, potreste perdere la scomparsa di un codice non inutilizzato e poi impiegare un po 'di tempo per capirlo e rendersi conto che è necessario verificare le versioni precedenti. Quello che faccio di solito è il primo commento: cose con tag task (TODO, TOREVIEW, TODELETE), un tag name (per tracciare l'autore senza guardare l'SCM) e timestamp (lo stesso motivo) con una motivazione per commentare le cose su. Poi la prossima volta che sfoglio questo pezzo di codice, e se nulla è stato sollevato in un incontro a riguardo, lo rimuovo. – haylem

+0

@haylem, molti IDE moderni possono rilevare il codice inutilizzato. Sebbene in C++ potrebbe non essere affidabile come per es. in Java, è ancora un aiuto. Inoltre, quando vedi questo codice, perché non chiedi a uno (o più) altri sviluppatori di confermare subito che può essere rimosso in sicurezza? E ultimo (ma non meno importante), con un buon set di test di integrazione/unità eseguito automaticamente dopo ogni commit, puoi essere molto più audace :-) –

+0

Ovviamente cerco di chiedere ai miei colleghi sviluppatori, ma non è insolito che sia qualcosa di implementato più di 5 anni fa e da qualcuno che ha lasciato l'azienda, e in alcuni casi non sappiamo nemmeno chi fosse a causa delle migrazioni di codebase errate tra SCM. Altrimenti, sono con voi sul principio di mantenerlo veloce e pulito. – haylem

4

continue è utile in un ciclo ad alta complessità. È una cattiva pratica usarlo per commentare il codice rimanente di un ciclo anche per il debugging temporaneo poiché la gente tende a dimenticare ...