Abbruchbedingung: != vs. <
-
Ich frage mich gerade, welche Variante man bevorzugt nehmen sollte? Bei Iteratoren verwenden die meisten glaub !=, aber wieso, ist die Überprüfung damit performanter?
/* einegbauter Typ */ for(int i=0; i<5; ++i); // oder for(int i=0 i!=5; ++i); /* Iterator */ for(it=vec.begin() ; it<vec.end(); ++it); // oder for(it=vec.begin() ; it!=vec.end(); ++it);
-
Hallo,
bei eingebauten Typen nehme ich eigentlich immer <, damit kann es nicht passieren, dass wenn man die Laufvariable zusätzlich im Schleifenkörper ändert man aus Versehen "über" den Endwert hinaus rutscht.
Bei Iteratoren Typischerweise !=, wobei ich mich gerade Frage, wenn der Iterator bei vector.end() angekommen ist und dann inkrementiert wird, bleibt er doch eigentlich bei vector.end() oder?
Grüße
foxx.
-
Gugelmoser schrieb:
Ich frage mich gerade, welche Variante man bevorzugt nehmen sollte? Bei Iteratoren verwenden die meisten glaub !=, aber wieso, ist die Überprüfung damit performanter?
Kann passieren. Stell Dir eine verkettet Liste vor. < müßte sich durchhangeln in O(n), während != instant ist.
Deswegen nehme ich immer !=. Will ja nicht nachdenken müssen, welchen Typ meine Laufvariable gerade hat.
-
zachery_foxx schrieb:
Hallo,
bei eingebauten Typen nehme ich eigentlich immer <, damit kann es nicht passieren, dass wenn man die Laufvariable zusätzlich im Schleifenkörper ändert man aus Versehen "über" den Endwert hinaus rutscht.
Typischer Fall von: Stilverlust als Folge von vorherigem Stilverlust.
-
zachery_foxx schrieb:
Bei Iteratoren Typischerweise !=, wobei ich mich gerade Frage, wenn der Iterator bei vector.end() angekommen ist und dann inkrementiert wird, bleibt er doch eigentlich bei vector.end() oder?
Wie meinst du das? Das Inkrementieren findet ja immer am Ende einer for-Schleife statt. Wenn also der Iterator bei vector.end() angekommen ist, dann läuft die Schleife ja nicht mehr durch und damit gibts auch kein Inkrement mehr.
volkard schrieb:
Kann passieren. Stell Dir eine verkettet Liste vor. < müßte sich durchhangeln in O(n), während != instant ist.
Deswegen nehme ich immer !=. Will ja nicht nachdenken müssen, welchen Typ meine Laufvariable gerade hat.
sehr gutes Argument.
-
Bei vector ist der end()-Iterator definiert als der Iterator auf das Element eins hinter dem Ende. Wenn man den inkrementiert ist man zwei hinter dem Ende. Und vermutlich ist das dann auch undefiniertes Verhalten (es könnte z.B. was überlaufen, wenn der vector maximal groß ist), aber das schau ich nun nicht im Standard nach.
-
Hat es denn von der Einheitlichkeit abgesehen noch irgendwelche Nachteile >< statt != zu benutzen bei Basistypen? Oder sieht's nur schöner aus?
Zum Ändern von Laufvariablen im Schleifenkörper: ich muss gestehen, dass mir spontan kein Beispiel einfällt, wo ich das mal gemacht hätte... war nur eine Überlegung. Außerdem finde ich "<" den schöneren Ausdruck (vom Verstehen her, denn es heißt ja tue etwas solange i kleiner ist als 5, während i hochgezählt wird...)

-
Der ++-Operator setzt für Input-Iteratoren (und damit auch ein forward-, bidirectionale oder random-access-Iteratoren) voraus, dass der Operand dereferenzierbar ist (Tabelle 107, 24.2.3). Das ist für den end-Iterator nicht der Fall. Der Versuch führt folglich zu UB.
-
< nehm ich bei Schleifen, bei denen ich nicht weiß, ob das Ende genau erreicht wird. Weil die Schrittweite variabel oder irgendwas außer 1 oder -1 ist. Sonst !=, dann sieht man nämlich direkt, dass nach Ende der Schleife die Schleifenbedingung mit == gelten muss.
-
SeppJ schrieb:
Wenn man den inkrementiert ist man zwei hinter dem Ende. Und vermutlich ist das dann auch undefiniertes Verhalten (es könnte z.B. was überlaufen, wenn der vector maximal groß ist), aber das schau ich nun nicht im Standard nach.
Eine gute Implementierung wirft dann in eh ein assert.
-
edit: Ich glaube, ich habe dich falsch verstanden.