it-swarm.com.de

Durchlaufen Sie einen C ++ - Vektor mit einer 'for'-Schleife

Ich bin neu in der C++ - Sprache. Ich habe angefangen, Vektoren zu verwenden, und habe festgestellt, dass der erste Parameter der for -Schleife in dem gesamten Code, den ich sehe, um einen Vektor über Indizes zu durchlaufen, immer etwas ist, das auf dem Vektor basiert. In Java Ich könnte so etwas mit einer ArrayList machen:

for(int i=0; i < vector.size(); i++){
   vector[i].doSomething();
}

Gibt es einen Grund, warum ich das in C++ nicht sehe? Ist es schlechte Praxis?

112
Flynn

Gibt es einen Grund, warum ich das in C++ nicht sehe? Ist es eine schlechte Praxis?

Nein, es ist keine schlechte Praxis, aber es macht Ihren Code sicher Flexibilität.

In der Regel werden in C++ 11 für den Code zum Iterieren über Containerelemente Iteratoren verwendet, etwa:

std::vector<int>::iterator it = vector.begin();

Dies liegt daran, dass der Code dadurch flexibler wird.

Alle Standard-Bibliothekscontainer unterstützen und stellen Iteratoren bereit. Wenn Sie zu einem späteren Zeitpunkt einen anderen Container wechseln müssen, muss dieser Code nicht geändert werden.

Anmerkung: Das Schreiben von Code, der mit jedem möglichen Standardbibliothekscontainer funktioniert, ist nicht so einfach möglich, wie es anscheinend scheint.

78
Alok Save

Der Grund, warum Sie eine solche Praxis nicht sehen, ist ziemlich subjektiv und kann keine eindeutige Antwort geben, da ich viele Codes gesehen habe, die Ihren erwähnten Weg anstelle von iterator -Stilcode verwenden.

Das Folgende kann Gründe dafür sein, dass Personen vector.size() nicht in Betracht ziehen:

  1. Paranoid sein, wenn es darum geht, size() jedes Mal in der Schleifenbedingung aufzurufen. Es ist jedoch entweder kein Problem oder es kann trivial behoben werden
  2. Bevorzugen Sie std::for_each() vor der for -Schleife
  3. Wenn Sie den Container später von std::vector Auf einen anderen ändern (z. B. map, list), muss auch der Schleifenmechanismus geändert werden, da nicht jeder Container die Schleifenart size() unterstützt

C++ 11 bietet eine gute Möglichkeit, sich durch die Container zu bewegen. Das nennt man "Range Based for Loop" (oder "Enhanced for Loop" in Java).

Mit wenig Code können Sie den gesamten Code durchlaufen (obligatorisch!) std::vector:

vector<int> vi;
...
for(int i : vi) 
  cout << "i = " << i << endl;
89
iammilind

Die sauberste Methode zum Durchlaufen eines Vektors ist die Verwendung von Iteratoren:

for (auto it = begin (vector); it != end (vector); ++it) {
    it->doSomething ();
}

oder (äquivalent zu oben)

for (auto & element : vector) {
    element.doSomething ();
}

Vor C++ 0x müssen Sie auto durch den Iteratortyp ersetzen und Mitgliedsfunktionen anstelle von globalen Funktionen verwenden, die beginnen und enden.

Das haben Sie wahrscheinlich gesehen. Gegenüber dem von Ihnen erwähnten Ansatz besteht der Vorteil darin, dass Sie nicht stark von der Art von vector abhängig sind. Wenn Sie vector in eine andere Klasse vom Typ "Auflistung" ändern, funktioniert Ihr Code wahrscheinlich weiterhin. Sie können jedoch auch in Java) etwas Ähnliches tun. Konzeptionell gibt es keinen großen Unterschied; C++ verwendet jedoch Vorlagen, um dies zu implementieren (im Vergleich zu Generika in Java), daher der Ansatz funktioniert für alle Typen, für die begin- und end-Funktionen definiert sind, auch für Nichtklassentypen wie statische Arrays. Siehe hier: Wie funktioniert die bereichsbezogene Arbeitsweise?) für einfache Arrays?

71
JohnB

Der richtige Weg dazu ist:

for(std::vector<T>::iterator it = v.begin(); it != v.end(); ++it) {
    it->doSomething();
 }

Wobei T der Typ der Klasse innerhalb des Vektors ist. Wenn die Klasse beispielsweise CActivity lautete, schreiben Sie CActivity anstelle von T.

Diese Art von Methode funktioniert auf jeder STL (nicht nur auf Vektoren, was ein bisschen besser ist).

Wenn Sie weiterhin Indizes verwenden möchten, gehen Sie folgendermaßen vor:

for(std::vector<T>::size_type i = 0; i != v.size(); i++) {
    v[i].doSomething();
}
33
DiGMi

Es gibt einige gute Gründe, Iteratoren zu verwenden, von denen einige hier erwähnt werden:

Ein späterer Containerwechsel macht Ihren Code nicht ungültig.

d. h., wenn Sie von einem std :: vector zu einer std :: list oder std :: set wechseln, können Sie keine numerischen Indizes verwenden, um zu Ihrem enthaltenen Wert zu gelangen. Die Verwendung eines Iterators ist weiterhin gültig.

Laufzeitüberwachung ungültiger Iterationen

Wenn Sie Ihren Container in der Mitte Ihrer Schleife ändern, wird bei der nächsten Verwendung Ihres Iterators eine ungültige Iteratorausnahme ausgelöst.

8
Eddie Parker

Ich war überrascht, dass niemand erwähnt hat, dass das Durchlaufen eines Arrays mit einem Ganzzahlindex das Schreiben von fehlerhaftem Code erleichtert, indem ein Array mit dem falschen Index subskribiert wird. Wenn Sie beispielsweise geschachtelte Schleifen haben, in denen i und j als Indizes verwendet werden, können Sie ein Array mit j anstelle von i falsch subskribieren und daher ein einfügen Fehler in das Programm.

Im Gegensatz dazu sind die anderen hier aufgeführten Formen, nämlich die bereichsbasierte for - Schleife und die Iteratoren, viel weniger fehleranfällig. Die Semantik der Sprache und der Typprüfungsmechanismus des Compilers verhindern, dass Sie versehentlich mit dem falschen Index auf ein Array zugreifen.

4

Mit STL verwenden Programmierer iterators zum Durchlaufen von Containern, da Iterator ein abstraktes Konzept ist, das in allen Standardcontainern implementiert ist. Beispielsweise, std::list hat keine operator [] überhaupt.

4
ForEveR