Angenommen, Sie haben die folgende for
Schleife *:
for (int i = 0; i < 10; ++i) {
// ...
}
Das könnte man auch so schreiben:
for (int i = 0; i != 10; ++i) {
// ...
}
Die Endergebnisse sind die gleichen. Gibt es also echte Argumente dafür, eins übereinander zu verwenden? Persönlich benutze ich die erstere, falls i
aus irgendeinem Grund etwas schief geht und der Wert 10 übersprungen wird.
* Entschuldigen Sie die Verwendung von magischen Zahlen, aber es ist nur ein Beispiel.
int i = 10; while(i --> 0) { /* stuff */ }
while ((i--) > 0)
Antworten:
Der Grund, sich für das eine oder andere zu entscheiden, liegt in der Absicht und damit in der besseren Lesbarkeit .
Absicht: Die Schleife sollte so lange laufen, wie sie
i
kleiner als 10 ist, und nicht so lange, wie siei
nicht gleich 10 ist. Auch wenn letzteres in diesem speziellen Fall gleich sein mag, ist es nicht das, was Sie meinen, und sollte es auch nicht so geschrieben werden.Lesbarkeit: Wenn Sie aufschreiben, was Sie meinen, ist es auch einfacher zu verstehen. Wenn Sie zum Beispiel verwenden
i != 10
, könnte sich jemand fragen, ob in der Schleife ein Wegi
größer als 10 werden könnte und ob die Schleife fortgesetzt werden sollte diefor
-Anweisung, aber das bedeutet nicht, dass die Leute es nicht tun und als Ergebnis erwarten die Betreuer es).quelle
i
"kleiner als 10" ist. Sie sollte so lange laufen, wie die (in diesem Fall) obere Grenze nicht erreicht wird. Wenn Sie das C ++ - Intervall / Iterator-Bereichs-Grundprinzip verwenden, ist es weitaus logischer, dies über auszudrücken!=
als<
.<
genau aus.for
Schleife. Mit<
hier wäre dumm. Auch Deckard scheint das anzuerkennen. Ich stimme seinem Kommentar als Antwort auf meinen sehr zu.!=
Das
<
Muster ist im Allgemeinen verwendbar, auch wenn das Inkrement nicht genau 1 ist.Auf diese Weise können Schleifen unabhängig von ihrer tatsächlichen Ausführung auf eine einzige übliche Weise ausgeführt werden.
quelle
i
, innerhalb der Schleife völlig sicher zu modifizieren, wenn nötig.<
, z. B. Iteratoren über eine Sequenz, und dies!=
wäre eine einzige gängige Methode, um Schleifen in C ++ auszuführen.<
Muster, weil es einen Tastendruck anstelle von zwei mit dem>
Muster und vier mit erfordert!=
. Es ist wirklich eine Frage der OCD-ähnlichen Effizienz.In C ++ lautet die Empfehlung von Scott Myers in „Effektiveres C ++“ (Punkt 6), immer die zweite zu verwenden, es sei denn, Sie haben einen Grund, dies nicht zu tun, da dies bedeutet, dass Sie für Iterator- und Ganzzahlindizes dieselbe Syntax verwenden, sodass Sie nahtlos zwischen
int
Iterator und Iterator wechseln können ohne Änderung der Syntax.In anderen Sprachen trifft dies nicht zu, weshalb ich
<
es wahrscheinlich vorziehen würde, weil Thorbjørn Ravn Andersen das so meint.By the way, neulich war ich Rücksprache mit einem anderen Entwickler und er sagte , der Grund zu bevorzugen
<
über!=
, weili
nicht versehentlich um mehr als eins erhöhen, und das könnte die Abbruchbedingung verursacht nicht erfüllt werden; Das ist meiner Meinung nach eine Menge Unsinn.quelle
<
als defensiveres Programmieren als!=
damals ...<
ist defensiver und meine Kollegen hassen es, wenn ich schreibe,!=
also nicht. Es gibt jedoch einen Fall für!=
in C ++ und das ist, was ich vorgestellt habe.i++
besteht darin, eine while-Schleife in eine for-Schleife umzuwandeln. Ich bin mir nicht sicher, ob es besser ist, die Hälfte der Iterationen zu haben als eine (nahezu) Endlosschleife. Letzteres würde den Fehler wahrscheinlich offensichtlicher machen.Die Verwendung von (i <10) ist meiner Meinung nach sicherer. Es wird die maximale Anzahl möglicher Beendigungsfälle abgefangen - alles, was größer oder gleich 10 ist. Vergleichen Sie dies mit dem anderen Fall (i! = 10); es fängt nur einen möglichen Abbruchfall auf - wenn ich genau 10 bin.
Ein Nebenprodukt davon ist, dass es die Lesbarkeit verbessert. Sollte das Inkrement etwas anderes 1 sein, kann dies außerdem dazu beitragen, die Wahrscheinlichkeit eines Problems zu minimieren, falls wir beim Schreiben des Beendigungsfalls einen Fehler machen.
Erwägen:
Obwohl beide Fälle wahrscheinlich fehlerhaft / falsch sind, ist der zweite wahrscheinlich MEHR falsch, da er nicht beendet wird. Der erste Fall wird beendet und es besteht eine höhere Wahrscheinlichkeit, dass er an der richtigen Stelle beendet wird, obwohl 14 wahrscheinlich die falsche Zahl ist (15 wäre wahrscheinlich besser).
quelle
Hier ist eine weitere Antwort, die noch niemand gefunden zu haben scheint.
for
Schleifen sollten verwendet werden, wenn Sie eine Sequenz durchlaufen müssen . Verwenden!=
ist die präziseste Methode, um die Abschlussbedingung für die Schleife anzugeben. Die Verwendung eines weniger restriktiven Operators ist jedoch eine sehr verbreitete Defensiv-Programmiersprache. Für ganze Zahlen spielt es keine Rolle - es ist nur eine persönliche Wahl ohne ein spezifischeres Beispiel. Durchlaufen Sie Sammlungen mit Iteratoren, die Sie!=
aus den von anderen angegebenen Gründen verwenden möchten . Wenn Sie Sequenzen vonfloat
oder berücksichtigendouble
, dann möchten Sie dies unbedingt vermeiden!=
.Was ich darauf hinweisen wollte, ist, dass
for
es verwendet wird, wenn Sie über eine Sequenz iterieren müssen. Die generierte Sequenz hat einen Startpunkt, ein Intervall und eine Abbruchbedingung. Diese sind in derfor
Erklärung kurz angegeben. Wenn Sie feststellen, dass Sie entweder (1) den Step-Teil vonfor
oder (2) so etwas wietrue
die Guard-Bedingung nicht angeben, sollten Sie keinefor
Schleife verwenden!Die
while
Schleife wird verwendet, um die Verarbeitung fortzusetzen, solange eine bestimmte Bedingung erfüllt ist. Wenn Sie keine Sequenz verarbeiten, möchten Sie wahrscheinlichwhile
stattdessen eine Schleife. Die Argumente für die Schutzbedingung sind hier ähnlich, aber die Entscheidung zwischen awhile
und einerfor
Schleife sollte sehr bewusst sein. Diewhile
Schleife wird in C ++ - Kreisen IMO unterschätzt.Wenn Sie eine Sammlung von Elementen verarbeiten (eine sehr häufige
for
Verwendung von Schleifen), sollten Sie wirklich eine spezialisiertere Methode verwenden. Leiderstd::for_each
ist in C ++ aus mehreren Gründen ziemlich schmerzhaft. In vielen Fällen führt das Trennen des Körpers einerfor
Schleife in einer freistehenden Funktion (obwohl dies etwas schmerzhaft ist) zu einer viel saubereren Lösung. Wenn sie mit Sammlungen arbeiten, betrachtenstd::for_each
,std::transform
oderstd::accumulate
. Die Implementierung vieler Algorithmen wird auf diese Weise präzise und kristallklar. Ganz zu schweigen davon, dass Sie sich beim Isolieren des Schleifenkörpers in eine separate Funktion / Methode auf den Algorithmus, seine Eingabeanforderungen und Ergebnisse konzentrieren müssen.Wenn Sie Java, Python, Ruby oder sogar C ++ 0x verwenden , sollten Sie eine geeignete Auflistung für jede Schleife verwenden. Wenn C ++ - Compiler diese Funktion implementieren,
for
verschwinden eine Reihe von Schleifen sowie diese Art von Diskussionen.quelle
while
,for
undforeach
(oder Sprache gleichwertig)while
Schleife verwendet, um die Verarbeitung fortzusetzen, bis eine bestimmte Bedingung nicht mehr erfüllt ist<
) oder dass der Operator in den fehlgeschlagenen Werten nachsichtig ist (!=
).Wenn Sie "weniger als" verwenden, ist dies (normalerweise) semantisch korrekt. Sie meinen also, dass Sie bis zu
i
10 zählen müssen, damit "weniger als" Ihre Absichten klar zum Ausdruck bringt. Die Verwendung von "ungleich" funktioniert offensichtlich in Fällen virtueller Anrufe, vermittelt jedoch eine etwas andere Bedeutung. In einigen Fällen ist dies vielleicht das, was Sie brauchen, aber meiner Erfahrung nach war dies nie der Fall. Wenn Sie wirklich einen Falli
gehabt hätten, in dem möglicherweise mehr oder weniger als 10 vorliegen, Sie aber eine Schleife ausführen möchten, bis der Wert 10 erreicht ist, müsste dieser Code wirklich sehr deutlich kommentiert werden und könnte wahrscheinlich besser mit einem anderen Konstrukt wie z alswhile
Schleife vielleicht.quelle
Ein Grund, warum ich a
less than
gegenüber a favorisieren würde,not equals
ist, als Wache zu fungieren. Unter bestimmten Umständen (schlechte Programmierung oder Desinfektion) kann dasnot equals
übersprungen werden, obwohlless than
es immer noch gültig ist .Hier ist ein Beispiel, in dem das Fehlen einer Desinfektionsprüfung zu merkwürdigen Ergebnissen geführt hat: http://www.michaeleisen.org/blog/?p=358
quelle
Hier ist ein Grund, warum Sie vielleicht lieber verwenden
<
als!=
. Wenn Sie eine Sprache mit globalem Variablenumfang verwenden, was passiert, wenn anderer Code geändert wirdi
? Wenn Sie verwenden ,<
anstatt!=
, passiert das Schlimmste, ist , dass die Iteration beendet schneller: vielleicht einige andere Code - Schritteni
durch Zufall, und Sie ein paar Iterationen in der for - Schleife überspringen. Aber was passiert, wenn Sie eine Schleife von 0 bis 10 durchführen und die Schleife auf 9 wechselt und einige falsch geschriebene Thread-Inkrementei
aus irgendeinem seltsamen Grund. Dann beendet Ihre Schleife diese Iteration und erhöht sie,i
so dass der Wert jetzt 11 ist. Da die Schleife die Ausgangsbedingung (i
nie gleich 10) übersprungen hat , wird sie nun eine Endlosschleife ausführen.Es muss nicht unbedingt eine besonders ausgeflippte Logik vom Typ Threading und globale Variablen sein, die dies verursacht. Möglicherweise schreiben Sie gerade eine Schleife, die zurückverfolgt werden muss. Wenn Sie
i
innerhalb der Schleife mutieren und Ihre Logik durcheinander bringen,!=
ist es weniger wahrscheinlich, dass Sie sich in einer Endlosschleife befinden , wenn Sie eine Obergrenze anstelle von a haben .quelle
In der Embedded-Welt, insbesondere in lauten Umgebungen, können Sie sich nicht darauf verlassen, dass der Arbeitsspeicher ordnungsgemäß funktioniert. In einer Bedingung (für, während, wenn), in der Sie mit '==' oder '! =' Vergleichen, laufen Sie immer Gefahr, dass Ihre Variablen den entscheidenden Wert überspringen, der die Schleife beendet - dies kann katastrophale Folgen haben - Mars Lander Level Konsequenzen. Die Verwendung von "<" oder ">" in der Bedingung bietet eine zusätzliche Sicherheitsstufe, um die "unbekannten Unbekannten" abzufangen.
Im ursprünglichen Beispiel
i
würde der Vergleich '<' den Fehler sofort abfangen und die Schleife verlassen , wenn er aus unerklärlichen Gründen auf einen Wert größer als 10 katapultiert würde, aber '! =' Würde weiter hochzählen, bis eri
um die 0 herum und zurück gewickelt ist bis 10.quelle
for (i=4; i<length; i++) csum+=dat[i];
bei dem legitime Pakete immerlength
mindestens vier haben, aber möglicherweise fehlerhafte Pakete empfangen werden. Wenn unterschiedliche Pakettypen unterschiedliche Längenanforderungen haben, kann es wünschenswert sein, die Länge als Teil der Verarbeitung zu validieren, die für jeden Pakettyp unterschiedlich ist, aber die Prüfsumme zuerst als Teil der gemeinsamen Logik zu validieren. Wenn ein Paket mit geringer Länge empfangen wird, spielt es keine Rolle, ob die Prüfsummenberechnung "gut" oder "schlecht" ausgibt, aber es sollte nicht abstürzen.