493 Stimmen

Iteration über std::vector: Vorzeichenlose vs. vorzeichenbehaftete Indexvariable

Was ist der richtige Weg, um über einen Vektor in C++ zu iterieren?

Betrachten Sie diese beiden Codefragmente, dieses hier funktioniert gut:

for (unsigned i=0; i < polygon.size(); i++) {
    sum += polygon[i];
}

und dieses hier:

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

was dazu führt Warnung: Vergleich zwischen vorzeichenbehafteten und vorzeichenlosen Ganzzahlausdrücken.

Die unsigned Variable sieht für mich ein wenig beängstigend aus und ich weiß, dass unsigned Variablen gefährlich sein können, wenn sie nicht korrekt verwendet werden, also - ist das korrekt?

11 Stimmen

Die ununterzeichnete ist korrekt, weil polygon.size() vom Typ unsigned ist. Unsigned bedeutet immer positiv oder 0. Das ist alles, was es bedeutet. Wenn die Variable immer nur für Zähler verwendet wird, dann ist unsigned die richtige Wahl.

0 Stimmen

Um die Warnung bezüglich signed/unsigned zu lösen, ersetzen Sie einfach int durch uint (unsigned int) bei der Deklaration von i.

3 Stimmen

@AdamBruss .size() ist nicht vom Typ unsigned a.k.a. unsigned int. Es ist vom Typ std::size_t.

4voto

mmx Punkte 400975
for (std::vector::iterator it = polygon.begin(); it != polygon.end(); it++)
    sum += *it;

2 Stimmen

Für Vektor ist das in Ordnung, aber im Allgemeinen ist es besser, ++it anstelle von it++ zu verwenden, falls der Iterator selbst nicht trivial ist.

0 Stimmen

Persönlich benutze ich ++i, aber ich denke, die meisten Leute bevorzugen den i++-Stil (der Standard-VS-Code-Schnipsel für "for" ist i++). Nur so als Gedanke

0 Stimmen

@mehrdadaFshari Wen kümmert es, was "die meisten Leute" tun? "Die meisten Leute" liegen bei vielen Dingen falsch. Post-Inkrement/Dekrement, bei dem der Vorwert nie verwendet wird, ist falsch und ineffizient, zumindest in der Theorie - ungeachtet dessen, wie oft es blind in unterdurchschnittlichem Beispielcode überall verwendet wird. Du solltest keine schlechten Praktiken fördern, nur um Dinge vertrauter aussehen zu lassen für Leute, die es noch nicht besser wissen.

2voto

Charlie Martin Punkte 106684

Das erste ist typgerecht und in gewisser Hinsicht korrekt. (Wenn man darüber nachdenkt, kann die Größe niemals weniger als null sein.) Diese Warnung erscheint mir als einer der guten Kandidaten, um ignoriert zu werden.

2 Stimmen

Ich denke, es ist ein schrecklicher Kandidat, der ignoriert werden sollte - es ist leicht zu beheben, und gelegentlich treten echte Fehler auf, weil Vorzeichen-/Vorzeichenlose Werte unangemessen verglichen werden. Zum Beispiel in diesem Fall, wenn die Größe größer als INT_MAX ist, terminiert die Schleife nie.

0 Stimmen

... oder vielleicht wird es sofort beendet. Eines von beiden. Es hängt davon ab, ob der vorzeichenbehaftete Wert für den Vergleich in einen vorzeichenlosen Wert umgewandelt wird, oder ob der vorzeichenlose Wert in einen vorzeichenbehafteten umgewandelt wird. Auf einer 64-Bit-Plattform mit einem 32-Bit-Integer, wie z.B. win64, würde der Integer auf size_t erweitert, und die Schleife endet nie.

0 Stimmen

@SteveJessop: Du kannst nicht mit Sicherheit sagen, dass die Schleife niemals endet. Bei der Iteration, wenn i == INT_MAX ist, verursacht i++ ein undefiniertes Verhalten. An diesem Punkt kann alles passieren.

2voto

Toby Speight Punkte 24996

Überlegen Sie, ob Sie überhaupt iterieren müssen

Der Standardheader bietet uns dafür Einrichtungen:

using std::begin;  // ermöglicht die argumentabhängige Suche auch
using std::end;    // wenn der Container-Typ hier unbekannt ist
auto sum = std::accumulate(begin(polygon), end(polygon), 0);

Andere Funktionen in der Algorithmus-Bibliothek führen häufige Aufgaben aus - stellen Sie sicher, dass Sie wissen, was verfügbar ist, wenn Sie sich Aufwand sparen wollen.

1voto

Pierre Punkte 3764

Obskures, aber wichtiges Detail: Wenn Sie "for(auto it)" wie folgt angeben, erhalten Sie eine Kopie des Objekts, nicht das tatsächliche Element:

struct Xs{int i} x;
x.i = 0;
vector  v;
v.push_back(x);
for(auto it : v)
    it.i = 1;         // ändert nicht das Element v[0]

Um die Elemente des Vektors zu modifizieren, müssen Sie den Iterator als Referenz definieren:

for(auto &it : v)

1voto

Brett L Punkte 95

Wenn Ihr Compiler es unterstützt, könnten Sie eine for-Schleife mit Bereichsbasiertem Zugriff verwenden, um auf die Vektorelemente zuzugreifen:

vector vertices{ 1.0, 2.0, 3.0 };

for(float vertex: vertices){
    std::cout << vertex << " ";
}

Gibt aus: 1 2 3. Beachten Sie, dass Sie diese Technik nicht zum Ändern der Elemente des Vektors verwenden können.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X