C'è un motivo tecnico per usare> (<) invece di! = Quando si incrementa di 1 in un ciclo 'for'?


198

Non vedo quasi mai un forciclo come questo:

for (int i = 0; 5 != i; ++i)
{}

C'è un motivo tecnico da usare >o <invece di !=quando incrementare di 1 in un forciclo? O questa è più una convenzione?


104
Lo rende più leggibile, più, se mai cambiare i++per i+=2(ad esempio), verrà eseguito per un tempo molto lungo (o forse per sempre). Ora, poiché in genere si utilizza <per quei casi in cui si incrementa l'iteratore di più di 1, è possibile utilizzare <anche per il caso in cui si incrementa di 1 (per coerenza).
Barak Manos,

112
5 != iè male
Slava,

27
Dovresti sempre essere consapevole di ciò che stai facendo, ma commetterai comunque degli errori. L'uso di <riduce la possibilità che qualcuno introduca un bug in questo codice.
Aurast,

40
@OleTange Se stai iterando usando numeri in virgola mobile sei già fregato ..
CaptainCodeman

29
@Slava ... non male. Apparentemente non sei mai stato morso in C da un semplice refuso che fa la differenza tra if ( i == 5 ) ...e if ( i = 5 ). Cose molto diverse. L'inversione degli operandi evita il problema: poiché i letterali non lo sono lvals, non possono essere assegnati e il compilatore si lancia sul refuso. @Zingam: buona programmazione difensiva!
Nicholas Carey,

Risposte:


303
while (time != 6:30pm) {
    Work();
}

Sono le 18:31 ... Accidenti, adesso la mia prossima possibilità di tornare a casa è domani! :)

Questo per mostrare che la restrizione più forte mitiga i rischi ed è probabilmente più intuitiva da capire.


25
A volte, il tentativo di "mitigare i rischi" finisce per nascondere il bug. Se il design del loop dovrebbe impedire alle 18:30 di passare inosservato, l'utilizzo <nasconderà il bug ma l'utilizzo !=renderebbe ovvio che c'è un problema.
Adrian McCarthy,

27
@AdrianMcCarthy: non necessariamente; potrebbe semplicemente introdurre un secondo bug, rendendo più difficile la diagnosi .
Corse della leggerezza in orbita,

4
@AdrianMcCarthy: è un po 'il mio punto; potresti averne alcuni esempi che non hai ancora visto;)
Lightness Races in Orbit

6
Gli iteratori sono un perfetto esempio del punto @AdrianMcCarthy credo. Il confronto consigliato per loro è! = Anziché <.
Taekahn,

5
Ho visto esattamente questo errore (e ha causato 3 mesi di debug) - ma questa risposta non ha assolutamente ragione. Nell'esempio dato è impossibile perdere la condizione finale. Si potrebbe anche dire che scegliere consapevolmente! = Over <è una forte affermazione di questo fatto. Mitigare un rischio che non esiste definitivamente è un odore di codice per me. (Detto questo, puoi anche sostenere che <è idiomatico, che è una buona ragione per usarlo come qualsiasi altro.)
Ian Goldby

95

Non c'è motivo tecnico. Ma esiste una mitigazione del rischio, della manutenibilità e una migliore comprensione del codice.

<o >sono restrizioni più forti di !=e soddisfano esattamente lo stesso scopo nella maggior parte dei casi (direi anche in tutti i casi pratici).

C'è una domanda duplicata qui ; e una risposta interessante .


6
Esistono alcuni tipi, come gli iteratori, che non supportano <o>, ma supportano == e! =.
Simon B,

1
È un ciclo for con int . Nessun iteratore.
Ely,

7
"Ma c'è mitigazione del rischio, manutenibilità e migliore comprensione del codice". Tutti questi sono, giustamente, ragioni tecniche. :-)
TJ Crowder,

@TJCrowder Che tipo di ragione è quando vuoi solo parlare di ciò che le macchine faranno di conseguenza?
Brilliand,

1
@DanSheppard Considererei generalmente la mitigazione del rischio e la manutenibilità come ragioni di business, e una migliore comprensione del codice come un motivo sociale (anche se questi motivi sono tutti applicati a una questione tecnica in questo caso). Le considerazioni sulla "mitigazione del rischio" non sono in alcun modo limitate alle questioni tecniche e le considerazioni sulla "migliore comprensione del codice" possono cambiare se ti ritrovi a lavorare con un diverso gruppo di persone (anche se le macchine coinvolte non cambiano affatto ).
Brilliand,

85

Sì, c'è un motivo. Se scrivi un (semplice vecchio indice basato) per un ciclo come questo

for (int i = a; i < b; ++i){}

quindi funziona come previsto per qualsiasi valore di ae b(cioè zero iterazioni quando a > binvece di infinito se l'hai usato i == b;).

D'altra parte, per gli iteratori che scriveresti

for (auto it = begin; it != end; ++it) 

perché qualsiasi iteratore dovrebbe implementare un operator!=, ma non per ogni iteratore è possibile fornire un operator<.

Anche basato sulla portata per i loop

for (auto e : v)

non sono solo fantasiosi zuccheri, ma riducono in modo misurabile le possibilità di scrivere codice sbagliato.


4
Bell'esempio Sarei interessato a un caso !=invece di <. Personalmente non ho mai usato quello che penso.
Ely,

@Elyasin Non ne ho trovato uno buono e non ho voluto postarne uno cattivo: Immagina di avere una sorta di contenitore circolare, dove aumenti di + x modulo la dimensione del contenitore N e vuoi interrompere il ciclo quando raggiungere un certo indice .... beh, questo è un esempio davvero negativo. Forse ne troverò uno migliore
idclev 463035818,

Lo stesso ciclo con! = Anziché <chiarisce quale sia il vantaggio di <(o>) in questo contesto. for (int i=a; i != b; i++) {}
Paul Smith,

10
L'uso di qualsiasi cosa oltre !=agli iteratori è abbastanza pericoloso, perché a volte gli iteratori possono essere meno che comparati (ad esempio è un puntatore) ma il confronto non ha senso (è un elenco collegato).
Zan Lynx,

1
Impara a usare lo spazio bianco, sul serio.
Miles Rout,

70

Puoi avere qualcosa di simile

for(int i = 0; i<5; ++i){
    ...
    if(...) i++;
    ...
}

Se la variabile del ciclo è scritta dal codice interno, è i!=5possibile che il ciclo non venga interrotto. Questo è più sicuro per verificare la disuguaglianza.

Modifica sulla leggibilità. La forma di disuguaglianza è molto più frequentemente utilizzata. Pertanto, questo è molto veloce da leggere in quanto non c'è nulla di speciale da capire (il carico del cervello è ridotto perché l'attività è comune). Quindi è bello che i lettori facciano uso di queste abitudini.


6
Questo tipo di "if (condition) then i ++" interno è la prima cosa a cui ho pensato.
WernerCD,

3
Mi aspettavo che questa fosse la risposta più votata; Sono stato sorpreso che ho dovuto scorrere così lontano per trovarlo. Questo fa molto di più nel convincere un programmatore inesperto piuttosto che "beh, dovresti usare la condizione più forte". Le altre risposte, se rimangono in cima, dovrebbero incorporare questo come una spiegazione chiara e ovvia di ciò che può andare storto con il codice proposto da OP.
msouth,

1
@msouth Sono pienamente d'accordo, ma il mio POV è abbastanza soggettivo;)
johan d

3
@msouth Lo adoro quando un comportamento di produzione imprevisto espone i miei bug, vero? :-)
deworde

3
@msouth Senti, tutto ciò che dobbiamo fare è non commettere mai errori e tutto andrà bene. Semplici.
deworde,

48

E ultimo ma non meno importante, questo si chiama programmazione difensiva , il che significa prendere sempre il caso più forte per evitare errori attuali e futuri che influenzano il programma.

L'unico caso in cui non è necessaria la programmazione difensiva è quello in cui gli stati sono stati dimostrati da condizioni pre e post (ma poi, dimostrando che questo è il più difensivo di tutta la programmazione).


2
Un buon esempio a supporto di ciò: la memoria è vulnerabile ai bit flip ( SEU ) causati dalle radiazioni. Quando si utilizza una intper una i != 15condizione, il contatore funzionerà a lungo se viene capovolto qualcosa al di sopra del quarto bit, in particolare su macchine con sizeof(int)64. Le SEU sono una preoccupazione molto reale a quote più elevate o nello spazio (a causa di radiazioni più elevate) o in grandi supercomputer (perché è presente tanta memoria).
Josh Sanford,

2
Pensare che il tuo programma funzionerà correttamente quando le radiazioni stanno cambiando la tua memoria è un modo ottimistico e un modo di pensare anticatastrico ... buon commento! :)
Luis Colorado,

37

Direi che un'espressione piace

for ( int i = 0 ; i < 100 ; ++i )
{
  ...
}

è più espressivo di intenti di quanto non sia

for ( int i = 0 ; i != 100 ; ++i )
{
  ...
}

Il primo afferma chiaramente che la condizione è un test per un limite superiore esclusivo su un intervallo; quest'ultimo è un test binario di una condizione di uscita. E se il corpo del ciclo non è banale, potrebbe non essere evidente che l'indice venga modificato solo nell'istruzione forstessa.


13
"Voglio che questo ciclo venga eseguito al massimo 5 volte" vs. "Voglio eseguire questo ciclo tutte le volte che è necessario, tranne esattamente 5 volte, che non voglio."
vescovo,

+1 per menzionare il limite superiore di un intervallo. Penso che questo sia importante per intervalli numerici. ! = non definisce un intervallo corretto in un ciclo for come questi
element11

22

Gli iteratori sono un caso importante quando usi più spesso la !=notazione:

for(auto it = vector.begin(); it != vector.end(); ++it) {
 // do stuff
}

Concesso: in pratica scriverei lo stesso basandomi su un range-for:

for(auto & item : vector) {
 // do stuff
}

ma il punto rimane: normalmente si confrontano gli iteratori usando ==o !=.


2
Gli iteratori spesso hanno solo una nozione di uguaglianza / disuguaglianza e non un ordine, ecco perché li usi !=. Per esempio, in una std::vectorsi potrebbe usare <come l'iteratore è legato all'indice / puntatore, ma in un std::setnon esiste tale ordinamento rigoroso, come cammina un albero binario.
Martin C.

19

La condizione di loop è un invariante di loop forzato.

Supponiamo di non guardare il corpo del ciclo:

for (int i = 0; i != 5; ++i)
{
  // ?
}

in questo caso, sai all'inizio dell'iterazione del ciclo che inon è uguale 5.

for (int i = 0; i < 5; ++i)
{
  // ?
}

in questo caso, all'inizio dell'iterazione del loop iè inferiore a5 .

Il secondo è molto, molto più informazioni del primo, no? Ora, l'intento del programmatore è (quasi certamente) lo stesso, ma se stai cercando bug, avere fiducia nella lettura di una riga di codice è una buona cosa. E il secondo impone quell'invariante, il che significa che alcuni bug che ti morderebbero nel primo caso non possono semplicemente accadere (o non causare corruzione della memoria, nel secondo caso).

Sai di più sullo stato del programma, leggendo meno codice, con <che con !=. E sulle moderne CPU, impiegano lo stesso tempo di nessuna differenza.

Se il tuo inon è stato manipolato nel corpo del loop, ed è sempre stato aumentato di 1, ed è iniziato meno di 5, non ci sarebbe differenza. Ma per sapere se è stato manipolato, dovresti confermare ciascuno di questi fatti.

Alcuni di questi fatti sono relativamente facili, ma puoi sbagliarti. Controllare l'intero corpo del ciclo è, tuttavia, un dolore.

In C ++ puoi scrivere un indexestipo tale che:

for( const int i : indexes(0, 5) )
{
  // ?
}

fa la stessa cosa di uno dei due forloop precedenti , anche fino al compilatore ottimizzandolo fino allo stesso codice. Qui, tuttavia, sai che inon può essere manipolato nel corpo del loop, come viene dichiarato const, senza che il codice danneggi la memoria.

Più informazioni è possibile ottenere da una riga di codice senza dover comprendere il contesto, più è facile rintracciare ciò che non va. <nel caso di loop di numeri interi fornisce più informazioni sullo stato del codice su quella riga rispetto a quanto !=non faccia.



13

Può accadere che la variabile isia impostata su un valore elevato e se si utilizza semplicemente l' !=operatore, si finirà in un ciclo infinito.


1
Non proprio infinito: sulla maggior parte delle implementazioni di C, isi avvolgerà silenziosamente al massimo. Ma sì, molto probabilmente più a lungo di quanto tu sia disposto ad aspettare.
usr2564301,

12

Come puoi vedere dalle altre numerose risposte, ci sono ragioni per usare <invece di! = Che aiuterà in casi limite, condizioni iniziali, modifica involontaria del contatore di loop, ecc ...

Onestamente, non penso che tu possa sottolineare abbastanza l'importanza della convenzione. Per questo esempio sarà abbastanza facile per gli altri programmatori vedere cosa stai cercando di fare, ma provocherà un doppio tentativo. Uno dei lavori durante la programmazione è renderlo il più leggibile e familiare a tutti il ​​più possibile, quindi inevitabilmente quando qualcuno deve aggiornare / cambiare il tuo codice, non ci vuole molto sforzo per capire cosa stavi facendo in diversi blocchi di codice . Se vedessi qualcuno usarlo !=, immaginerei che ci fosse una ragione per cui lo usavano invece <e se fosse un grande giro guarderei tutto per cercare di capire cosa hai fatto che lo rendesse necessario ... tempo perso.


12

Come già detto da Ian Newson, non è possibile passare in modo affidabile su una variabile mobile e uscire con !=. Per esempio,

for (double x=0; x!=1; x+=0.1) {}

eseguirà effettivamente il ciclo per sempre, poiché 0,1 non può essere rappresentato esattamente in virgola mobile, quindi il contatore manca strettamente 1. Con < esso termina.

(Si noti tuttavia che è un comportamento sostanzialmente indefinito se si ottiene 0.9999 ... come l'ultimo numero accettato - che tipo di violazione viola il presupposto - o se si esce già a 1.000000000000000001.)


10

Prendo l'aggettivo "tecnico" per indicare comportamenti / stranezze del linguaggio ed effetti collaterali del compilatore come l'esecuzione del codice generato.

A tal fine, la risposta è: no (*). Il simbolo (*) è "consultare il manuale del processore". Se si lavora con alcuni sistemi RISC o FPGA perimetrali, potrebbe essere necessario controllare quali istruzioni vengono generate e quanto costano. Ma se si sta utilizzando praticamente qualsiasi architettura moderna convenzionale, quindi non c'è una significativa differenza di livello di processore di costo tra lt, eq, nee gt.

Se si utilizza un caso limite si potrebbe trovare che !=richiede tre operazioni ( cmp, not, beq) contro due ( cmp, blt xtr myo). Ancora una volta, RTM in quel caso.

Per la maggior parte, i motivi sono difensivi / indurenti, specialmente quando si lavora con puntatori o loop complessi. Tener conto di

// highly contrived example
size_t count_chars(char c, const char* str, size_t len) {
    size_t count = 0;
    bool quoted = false;
    const char* p = str;
    while (p != str + len) {
        if (*p == '"') {
            quote = !quote;
            ++p;
        }
        if (*(p++) == c && !quoted)
            ++count;
    }
    return count;
}

Un esempio meno elaborato sarebbe dove si utilizzano i valori di ritorno per eseguire incrementi, accettando i dati da un utente:

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i != len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;

        std::cin >> step;
        i += step; // here for emphasis, it could go in the for(;;)
    }
}

Prova questo e inserisci i valori 1, 2, 10, 999.

Si potrebbe impedire questo:

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i != len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;
        std::cin >> step;
        if (step + i > len)
            std::cout << "too much.\n";
        else
            i += step;
    }
}

Ma quello che probabilmente volevi era

#include <iostream>
int main() {
    size_t len = 5, step;
    for (size_t i = 0; i < len; ) {
        std::cout << "i = " << i << ", step? " << std::flush;
        std::cin >> step;
        i += step;
    }
}

C'è anche una sorta di orientamento alla convenzione <, perché spesso si fa affidamento sull'ordinamento in contenitori standardoperator< , ad esempio, l'hashing in diversi contenitori STL determina l'uguaglianza dicendo

if (lhs < rhs) // T.operator <
    lessthan
else if (rhs < lhs) // T.operator < again
    greaterthan
else
    equal

Se lhserhs sono una classe definita dall'utente che scrive questo codice come

if (lhs < rhs) // requires T.operator<
    lessthan
else if (lhs > rhs) // requires T.operator>
    greaterthan
else
    equal

L'implementatore deve fornire due funzioni di confronto. Quindi <è diventato l'operatore preferito.


Per leggibilità i + = il passaggio dovrebbe essere nella parte per il controllo. Nel caso in cui dovessi fare un passo = 0
Mikkel Christiansen,

1
Mentre ciò aiuterebbe la leggibilità di un buon codice, volevo sottolineare il difetto nella versione errata
kfsone,

9

Esistono diversi modi per scrivere qualsiasi tipo di codice (di solito), in questo caso ci sono solo due modi (tre se conti <= e> =).

In questo caso, le persone preferiscono> e <per assicurarsi che anche se accade qualcosa di imprevisto nel loop (come un bug), non si ripeterà all'infinito (BAD). Considera il seguente codice, ad esempio.

for (int i = 1; i != 3; i++) {
    //More Code
    i = 5; //OOPS! MISTAKE!
    //More Code
}

Se usassimo (i <3), saremmo al sicuro da un ciclo infinito perché pone una restrizione maggiore.

È davvero la tua scelta se vuoi un errore nel tuo programma per chiudere tutto o continuare a funzionare con il bug lì.

Spero che questo abbia aiutato!


si potrebbe obiettare che il ciclo infinito sarebbe un buon indicatore dell'errore, ma poi un altro potrebbe sostenere che i = 5 non è necessariamente un errore
njzk2,

7

Il motivo più comune da utilizzare <è la convenzione. Più programmatori pensano ai loop come questo come "mentre l'indice si trova nell'intervallo" anziché "fino a quando l'indice non raggiunge la fine". C'è valore che aderisce alla convenzione quando puoi.

D'altra parte, molte risposte qui sostengono che l'uso del <modulo aiuta a evitare i bug. Direi che in molti casi questo aiuta solo a nascondere i bug. Se si suppone che l'indice del ciclo raggiunga il valore finale e, invece, in realtà vada oltre, allora sta accadendo qualcosa che non ti aspettavi che potrebbe causare un malfunzionamento (o essere un effetto collaterale di un altro bug). Il <sarà probabilmente ritardare la scoperta del bug. Il !=è più probabile che portare ad uno stallo, blocco, o anche un incidente, che vi aiuterà a individuare il bug prima. Prima viene trovato un bug, più economico è riparare.

Si noti che questa convenzione è peculiare dell'indicizzazione di array e vettori. Quando attraversi quasi qualsiasi altro tipo di struttura di dati, dovresti usare un iteratore (o puntatore) e verificare direttamente un valore finale. In questi casi devi assicurarti che l'iteratore raggiunga e non superi il valore finale effettivo.

Ad esempio, se stai passando attraverso una semplice stringa C, è generalmente più comune scrivere:

for (char *p = foo; *p != '\0'; ++p) {
  // do something with *p
}

di

int length = strlen(foo);
for (int i = 0; i < length; ++i) {
  // do something with foo[i]
}

Per prima cosa, se la stringa è molto lunga, la seconda forma sarà più lenta perché strlenè un'altra passaggio attraverso la stringa.

Con C ++ std :: string, useresti un intervallo basato su loop, un algoritmo standard o iteratori, anche se la lunghezza è prontamente disponibile. Se stai usando iteratori, la convenzione è di usare !=piuttosto che <, come in:

for (auto it = foo.begin(); it != foo.end(); ++it) { ... }

Allo stesso modo, iterare un albero o un elenco o un deque di solito comporta la ricerca di un puntatore nullo o altra sentinella invece di verificare se un indice rimane all'interno di un intervallo.


3
Hai perfettamente ragione a sottolineare l'importanza del linguaggio nella programmazione. Se guardo un po 'di codice e ha un modello familiare, non ho bisogno di perdere tempo a dedurlo, ma posso andare dritto al nocciolo. Immagino che sia la mia principale presa con i confronti di Yoda: non sembrano idiomatici, quindi finisco per leggerli due volte per essere sicuro che significano ciò che penso significhino.
Toby Speight,

7

Un motivo per non usare questo costrutto è rappresentato dai numeri in virgola mobile. !=è un paragone molto pericoloso da usare con i float poiché raramente valuterà vero anche se i numeri sembrano uguali. <o >rimuove questo rischio.


Se il tuo iteratore di loop è un numero in virgola mobile, il !=versus <è l'ultimo dei tuoi problemi.
Lundin,

7

Ci sono due ragioni correlate per seguire questa pratica che hanno entrambe a che fare con il fatto che un linguaggio di programmazione è, dopo tutto, un linguaggio che verrà letto dagli umani (tra gli altri).

(1) Un po 'di ridondanza. In linguaggio naturale di solito forniamo più informazioni di quelle strettamente necessarie, proprio come un codice di correzione degli errori. Qui le informazioni extra sono che la variabile loop i(vedi come ho usato la ridondanza qui? Se non sapevi cosa significhi 'variabile loop', o se hai dimenticato il nome della variabile, dopo aver letto "variabile loop i" hai il pieno informazioni) è inferiore a 5 durante il ciclo, non solo diverso da 5. La ridondanza migliora la leggibilità.

(2) Convenzione. Le lingue hanno modi standard specifici di esprimere determinate situazioni. Se non segui il modo stabilito di dire qualcosa, sarai comunque compreso, ma lo sforzo per il destinatario del tuo messaggio è maggiore perché alcune ottimizzazioni non funzioneranno. Esempio:

Non parlare della poltiglia calda. Illumina solo la difficoltà!

La prima frase è una traduzione letterale di un linguaggio tedesco. Il secondo è un linguaggio inglese comune con le parole principali sostituite da sinonimi. Il risultato è comprensibile ma ci vuole molto più tempo per capirlo:

Non battere il cespuglio. Spiega solo il problema!

Ciò è vero anche nel caso in cui i sinonimi utilizzati nella prima versione si adattino meglio alla situazione rispetto alle parole convenzionali nell'idioma inglese. Forze simili hanno effetto quando i programmatori leggono il codice. Questo è anche il motivo 5 != ie 5 > isono modi strani per dirlo a meno che tu non stia lavorando in un ambiente in cui è normale scambiare il più normale i != 5e i < 5in questo modo. Esistono comunità dialettali simili, probabilmente perché la coerenza rende più facile ricordare di scrivere al 5 == iposto del naturale ma soggetto a errori i == 5.


1
Ausgezeichnet . Allo stesso modo, non si scriverebbe il test come i < 17+(36/-3)(anche quando si tratta di costanti utilizzate altrove; quindi è necessario scrivere i loro nomi per chiarezza!).
usr2564301,

6

L'uso di confronti relazionali in questi casi è un'abitudine più popolare di ogni altra cosa. Ha guadagnato la sua popolarità ai tempi in cui considerazioni concettuali come le categorie di iteratori e la loro comparabilità non erano considerate prioritarie.

Direi che uno dovrebbe preferire usare confronti di uguaglianza invece di confronti relazionali quando possibile, poiché i confronti di uguaglianza impongono meno requisiti ai valori confrontati. Essere uguaglianza comparabile è un requisito minore rispetto a essere meno coordinabile .

Un altro esempio che dimostra l'applicabilità più ampia del confronto di uguaglianza in tali contesti è l'enigma popolare con l'attuazione unsigneddell'iterazione fino a 0. Può essere fatto come

for (unsigned i = 42; i != -1; --i)
  ...

Si noti che quanto sopra è ugualmente applicabile a iterazioni firmate e non firmate, mentre la versione relazionale si suddivide con tipi non firmati.


2

Oltre agli esempi, in cui la variabile di loop cambierà (involontariamente) all'interno del corpo, ci sono altre ragioni per usare gli operatori più piccoli o più grandi di:

  • Le negazioni rendono il codice più difficile da capire
  • <o >è solo un carattere, ma !=due

4
Il secondo proiettile è nella migliore delle ipotesi un motivo frivolo. Il codice dovrebbe essere corretto e chiaro. Compatto è molto meno importante.
Jonathan Leffler,

@JonathanLeffler Bene, in un REPL di TDD, quel personaggio in più è un nano-secondo in più per l'analisi, e volte un miliardo di iterazioni per trovare il bug causato dalla scrittura 5 != $i, che ha richiesto solo un intero secondo della mia vita. Uh ... ridacchiando
vescovo il

1

Oltre alle varie persone che hanno affermato che mitiga il rischio, riduce anche il numero di sovraccarichi di funzioni necessari per interagire con i vari componenti della libreria standard. Ad esempio, se vuoi che il tuo tipo sia memorizzabile in un std::set, o usato come chiave per std::map, o usato con alcuni degli algoritmi di ricerca e ordinamento, la libreria standard di solito usa std::lessper confrontare gli oggetti poiché la maggior parte degli algoritmi necessita solo di un rigoroso ordinamento debole . Quindi diventa una buona abitudine usare i <confronti invece dei !=confronti (dove ovviamente ha senso).


1
potresti avere ragione sul numero di sovraccarichi, ma quando si considerano i requisiti sugli oggetti, quindi per quasi tutti gli oggetti si può definire un !=operatore, ma non è sempre possibile definire un ordinamento debole e rigoroso. In questo senso !=sarebbe meglio, perché pone meno requisiti sul tipo. Tuttavia, resto ancora con <.
idclev 463035818,

0

Non ci sono problemi dal punto di vista della sintassi, ma la logica dietro quell'espressione 5!=inon è sana.

A mio avviso, l'utilizzo !=per impostare i limiti di un ciclo for non è logicamente corretto poiché un ciclo for incrementa o decrementa l'indice di iterazione, quindi impostando il ciclo su iterazione fino a quando l'indice di iterazione diventa fuori dai limiti (!= a qualcosa) non è un corretta attuazione.

Essa funzionerà, ma è incline a comportamenti scorretti in quanto la gestione dei dati di confine si perde quando si utilizza !=per un problema incrementale (il che significa che si sa fin dall'inizio se si incrementi o decrementi), ecco perché, invece !=della <>>==>sono utilizzati.


2
La logica va benissimo. Quando iè 5il ciclo termina. Intendevi dire qualcos'altro?
Dan Getz,

1
Se i dati non vengono trasferiti correttamente a causa del calore, le influenze elettromagnetiche del codice vengono eseguite per sempre. Se lo fai su una normale workstation o server con RAM ECC non c'è problema (né logico, tecnico né fisico)
Markus
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.