Was ist die richtige Methode zum Iterieren über einen Vektor in C ++?
Betrachten Sie diese beiden Codefragmente, dieses funktioniert gut:
for (unsigned i=0; i < polygon.size(); i++) {
sum += polygon[i];
}
und das hier:
for (int i=0; i < polygon.size(); i++) {
sum += polygon[i];
}
was erzeugt warning: comparison between signed and unsigned integer expressions
.
Ich bin neu in der Welt von C ++, daher unsigned
sieht die Variable für mich etwas beängstigend aus und ich weiß, dass unsigned
Variablen gefährlich sein können, wenn sie nicht richtig verwendet werden. Ist das also richtig?
.size()
ist nicht vom Typunsigned
akaunsigned int
. Es ist vom Typstd::size_t
.std::size_t
ist ein _implementierungsdefinierter Typedef. Siehe den Standard.std::size_t
Dies entspricht möglicherweiseunsigned
Ihrer aktuellen Implementierung, ist jedoch nicht relevant. Das Vorgeben, dies zu tun, kann zu nicht portierbarem Code und undefiniertem Verhalten führen.std::size_t
in der Praxis ist. Denken Sie, wir haben in diesem weitläufigen Strom von Kommentaren über 6 Jahre alles bisher behandelt?Antworten:
Informationen zum Rückwärtslaufen finden Sie in dieser Antwort .
Vorwärts iterieren ist fast identisch. Ändern Sie einfach die Iteratoren / Swap-Dekremente schrittweise. Sie sollten Iteratoren bevorzugen. Einige Leute sagen Ihnen, dass Sie
std::size_t
als Indexvariablentyp verwenden sollen. Dies ist jedoch nicht tragbar. Verwendensize_type
Sie immer das typedef des Containers (Während Sie im vorwärts iterierenden Fall nur mit einer Konvertierung davonkommen könnten, könnte es im rückwärts iterierenden Fall bei der Verwendung tatsächlich ganz schief gehenstd::size_t
, fallsstd::size_t
es breiter ist als das typedef vonsize_type
). ::Verwenden von std :: vector
Iteratoren verwenden
Wichtig ist, dass Sie immer das Präfix-Inkrement-Formular für Iteratoren verwenden, deren Definitionen Sie nicht kennen. Dadurch wird sichergestellt, dass Ihr Code so allgemein wie möglich ausgeführt wird.
Verwenden von Range C ++ 11
Indizes verwenden
Arrays verwenden
Iteratoren verwenden
Verwenden von Range C ++ 11
Indizes verwenden
Lesen Sie in der rückwärts iterierenden Antwort, zu welchem Problem der
sizeof
Ansatz führen kann.quelle
for (auto p : polygon){sum += p;}
Vier Jahre vergingen, Google gab mir diese Antwort. Mit dem Standard- C ++ 11 (auch bekannt als C ++ 0x ) gibt es tatsächlich eine neue angenehme Möglichkeit (zum Preis der Unterbrechung der Abwärtskompatibilität): das neue
auto
Schlüsselwort. Dies erspart Ihnen die Mühe, den Typ des zu verwendenden Iterators explizit angeben zu müssen (wobei der Vektortyp erneut wiederholt wird), wenn (für den Compiler) klar ist, welcher Typ verwendet werden soll. Mitv
Ihrem seinvector
, können Sie etwas tun , wie folgt:C ++ 11 geht noch weiter und bietet Ihnen eine spezielle Syntax zum Durchlaufen von Sammlungen wie Vektoren. Es beseitigt die Notwendigkeit, Dinge zu schreiben, die immer gleich sind:
Erstellen Sie eine Datei, um sie in einem Arbeitsprogramm anzuzeigen
auto.cpp
:Wenn Sie dies mit g ++ kompilieren , müssen Sie es normalerweise so einstellen, dass es mit dem neuen Standard funktioniert, indem Sie ein zusätzliches Flag angeben:
Jetzt können Sie das Beispiel ausführen:
Bitte beachten Sie, dass die Anweisungen zum Kompilieren und Ausführen spezifisch für den gnu c ++ - Compiler unter Linux sind. Das Programm sollte plattform- (und compiler-) unabhängig sein.
quelle
for (auto& val: vec)
std::vector<int> v = std::vector<int>();
oder hätten Sie ihnstd::vector<int> v;
stattdessen einfach verwenden können ?In dem speziellen Fall in Ihrem Beispiel würde ich die STL-Algorithmen verwenden, um dies zu erreichen.
Für einen allgemeineren, aber immer noch recht einfachen Fall würde ich gehen mit:
quelle
Zur Antwort von Johannes Schaub:
Das mag mit einigen Compilern funktionieren, aber nicht mit gcc. Das Problem hierbei ist die Frage, ob std :: vector :: iterator ein Typ, eine Variable (Mitglied) oder eine Funktion (Methode) ist. Wir bekommen den folgenden Fehler mit gcc:
Die Lösung verwendet das Schlüsselwort 'Typname' wie folgt:
quelle
T
es sich um ein Vorlagenargument handelt und der Ausdruckstd::vector<T*>::iterator
daher ein abhängiger Name ist. Damit ein abhängiger Name als Typ analysiert werden kann, muss ihm dastypename
Schlüsselwort vorangestellt werden , wie in der Diagnose angegeben.Ein Aufruf von
vector<T>::size()
gibt einen Wert vom Typ zurückstd::vector<T>::size_type
, nicht int, unsigned int oder anderweitig.Im Allgemeinen wird die Iteration über einen Container in C ++ mithilfe solcher Iteratoren durchgeführt .
Wobei T der Datentyp ist, den Sie im Vektor speichern.
Oder die verschiedenen Iterationsalgorithmen mit (
std::transform
,std::copy
,std::fill
,std::for_each
et cetera).quelle
Verwendung
size_t
:Wikipedia zitieren :
quelle
#include <cstddef>
statt<stddef.h>
oder, schlimmer noch, die Gesamtheit[c]stdlib
und die Verwendungstd::size_t
nicht die uneingeschränkte Version - und gleiche gilt für jede andere Situation , wo Sie haben die Wahl zwischen<cheader>
und<header.h>
.Ein bisschen Geschichte:
Verwenden Sie ein Vorzeichenbit, um darzustellen, ob eine Zahl negativ ist oder nicht.
int
ist ein vorzeichenbehafteter Datentyp, der positive und negative Werte enthalten kann (etwa -2 bis 2 Milliarden).Unsigned
kann nur positive Zahlen speichern (und da es kein bisschen an Metadaten verschwendet, kann es mehr speichern: 0 bis ungefähr 4 Milliarden).std::vector::size()
gibt ein zurückunsigned
, denn wie könnte ein Vektor eine negative Länge haben?Die Warnung sagt Ihnen, dass der rechte Operand Ihrer Ungleichheitsanweisung mehr Daten enthalten kann als der linke.
Wenn Sie einen Vektor mit mehr als 2 Milliarden Einträgen haben und eine Ganzzahl zum Indizieren verwenden, treten im Wesentlichen Überlaufprobleme auf (der int wird auf negative 2 Milliarden zurückgesetzt).
quelle
Normalerweise benutze ich BOOST_FOREACH:
Es funktioniert mit STL-Containern, Arrays, Strings im C-Stil usw.
quelle
Um vollständig zu sein, aktiviert die C ++ 11-Syntax nur eine andere Version für Iteratoren ( ref ):
Das ist auch bequem für die umgekehrte Iteration
quelle
In C ++ 11
Ich würde allgemeine Algorithmen verwenden
for_each
, um die Suche nach dem richtigen Typ von Iterator und Lambda-Ausdruck zu vermeiden, um zusätzliche benannte Funktionen / Objekte zu vermeiden.Das kurze "hübsche" Beispiel für Ihren speziellen Fall (vorausgesetzt, Polygon ist ein Vektor von ganzen Zahlen):
getestet auf: http://ideone.com/i6Ethd
Vergessen Sie nicht, Folgendes anzugeben : Algorithmus und natürlich Vektor :)
Microsoft hat tatsächlich auch ein schönes Beispiel dafür:
Quelle: http://msdn.microsoft.com/en-us/library/dd293608.aspx
quelle
quelle
Der erste ist typrichtig und im engeren Sinne korrekt. (Wenn Sie darüber nachdenken, kann die Größe niemals kleiner als Null sein.) Diese Warnung scheint mir jedoch einer der guten Kandidaten zu sein, um ignoriert zu werden.
quelle
i == INT_MAX
danni++
undefiniertes Verhalten. An diesem Punkt kann alles passieren.Überlegen Sie, ob Sie überhaupt iterieren müssen
Der
<algorithm>
Standard-Header bietet uns dafür folgende Möglichkeiten:Andere Funktionen in der Algorithmusbibliothek führen allgemeine Aufgaben aus. Stellen Sie sicher, dass Sie wissen, was verfügbar ist, wenn Sie sich Mühe sparen möchten.
quelle
Dunkles, aber wichtiges Detail: Wenn Sie wie folgt "for (auto it)" sagen, erhalten Sie eine Kopie des Objekts, nicht das eigentliche Element:
Um die Elemente des Vektors zu ändern, müssen Sie den Iterator als Referenz definieren:
quelle
Wenn Ihr Compiler dies unterstützt, können Sie einen Bereich verwenden, der auf basiert, um auf die Vektorelemente zuzugreifen:
Drucke: 1 2 3. Beachten Sie, dass Sie diese Technik nicht zum Ändern der Elemente des Vektors verwenden können.
quelle
Die beiden Codesegmente funktionieren gleich. Die vorzeichenlose int "-Route ist jedoch korrekt. Die Verwendung von vorzeichenlosen int-Typen funktioniert besser mit dem Vektor in der von Ihnen verwendeten Instanz. Wenn Sie die Elementfunktion size () für einen Vektor aufrufen, wird ein vorzeichenloser ganzzahliger Wert zurückgegeben, sodass Sie die Variable vergleichen möchten "i" auf einen Wert seines eigenen Typs.
Wenn Sie sich immer noch nicht sicher sind, wie "unsigned int" in Ihrem Code aussieht, versuchen Sie es mit "uint". Dies ist im Grunde eine verkürzte Version von "unsigned int" und es funktioniert genauso. Sie müssen auch keine anderen Header einfügen, um es zu verwenden.
quelle
Fügen Sie dies hinzu, da ich es in keiner Antwort erwähnt finden konnte: Für die indexbasierte Iteration können wir verwenden,
decltype(vec_name.size())
welche zu bewerten wärestd::vector<T>::size_type
Beispiel
quelle