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.

14voto

Igor Punkte 25698

Verwenden Sie size_t :

for (size_t i=0; i < polygon.size(); i++)

Zitat von Wikipedia:

Die Header-Dateien stdlib.h und stddef.h definieren einen Datentyp namens size_t, der verwendet wird, um die Größe eines Objekts darzustellen. Bibliotheksfunktionen, die Größen verwenden, erwarten, dass sie vom Typ size_t sind, und der sizeof-Operator ergibt size_t.

Der tatsächliche Typ von size_t ist plattformabhängig; ein häufiger Fehler besteht darin anzunehmen, dass size_t dasselbe wie unsigned int ist, was zu Programmfehlern führen kann, insbesondere da 64-Bit-Architekturen weit verbreiteter werden.

0 Stimmen

OK für Vektor, da es alle Objekte in einem Array speichern muss (selbst auch ein Objekt), aber ein std::list kann mehr als Elemente enthalten!

1 Stimmen

Size_t reicht normalerweise aus, um alle Bytes im Adressraum eines Prozesses aufzulisten. Obwohl ich verstehen kann, dass dies bei einigen exotischen Architekturen möglicherweise nicht der Fall ist, möchte ich mich lieber keine Gedanken darüber machen.

1 Stimmen

Meines Wissens wird empfohlen, #include anstelle von oder, schlimmer noch, der ganzen [c]stdlib zu verwenden, und std::size_t anstelle der unqualifizierten Version - und dasselbe gilt für jede andere Situation, in der man die Wahl zwischen und hat.

7voto

ecoffey Punkte 3173

Ein wenig Geschichte:

Um darzustellen, ob eine Zahl negativ ist oder nicht, verwendet der Computer ein 'Vorzeichen'-Bit. int ist ein vorzeichenbehafteter Datentyp, was bedeutet, dass er positive und negative Werte speichern kann (von etwa -2 Milliarden bis 2 Milliarden). Unsigned kann nur positive Zahlen speichern (und da es kein Bit für Metadaten verschwendet, kann es mehr speichern: von 0 bis etwa 4 Milliarden).

std::vector::size() gibt ein unsigned zurück, denn wie könnte ein Vektor eine negative Länge haben?

Die Warnung sagt dir, dass der rechte Operand deiner Ungleichungsanweisung mehr Daten aufnehmen kann als der linke.

Im Wesentlichen, wenn du einen Vektor mit mehr als 2 Milliarden Einträgen hast und einen Integer zum Indexieren verwendest, wirst du Überlaufprobleme haben (der int wird zurück auf negative 2 Milliarden zurückgesetzt).

6voto

Martin Cote Punkte 27446

Ich benutze normalerweise BOOST_FOREACH:

#include 

BOOST_FOREACH( vector_type::value_type& value, v ) {
    // mach etwas mit 'value'
}

Es funktioniert mit STL Containern, Arrays, C-Style Strings, etc.

2 Stimmen

Gute Antwort auf eine andere Frage (wie sollte ich einen Vektor iterieren?), aber überhaupt nicht das, was der OP gefragt hat (was ist die Bedeutung der Warnung bezüglich einer nicht signierten Variablen?)

3 Stimmen

Nun ja, er fragte, wie man am besten über einen Vektor iteriert. Also scheint das relevant genug zu sein. Die Warnung ist nur der Grund, warum er mit seiner aktuellen Lösung nicht zufrieden ist.

5voto

Jan Turoň Punkte 28722

Um vollständig zu sein, ermöglicht die C++11-Syntax nur eine weitere Version für Iteratoren (ref):

for(auto it=std::begin(polygon); it!=std::end(polygon); ++it) {
  // mache etwas mit *it
}

Was auch für die umgekehrte Iteration komfortabel ist

for(auto it=std::end(polygon)-1; it!=std::begin(polygon)-1; --it) {
  // mache etwas mit *it
}

5voto

jave.web Punkte 12114

In C++11

Ich würde allgemeine Algorithmen wie for_each verwenden, um nicht nach dem richtigen Typ des Iterators suchen zu müssen, und Lambda-Ausdrücke, um zusätzliche benannte Funktionen/Objekte zu vermeiden.

Das kurze "schöne" Beispiel für deinen speziellen Fall (vorausgesetzt, dass polygon ein Vektor von Ganzzahlen ist):

for_each(polygon.begin(), polygon.end(), [&sum](int i){ sum += i; });

getestet auf: http://ideone.com/i6Ethd

Vergiss nicht, zu inkludieren: algorithm und natürlich vector :)

Microsoft hat tatsächlich auch ein schönes Beispiel dazu:
Quelle: http://msdn.microsoft.com/en-us/library/dd293608.aspx

#include 
#include 
#include 
using namespace std;

int main() 
{
   // Erstelle ein Vektorobjekt, das 10 Elemente enthält.
   vector v;
   for (int i = 1; i < 10; ++i) {
      v.push_back(i);
   }

   // Zähle die Anzahl der geraden Zahlen im Vektor, indem
   // du die for_each-Funktion und ein Lambda verwendest.
   int evenCount = 0;
   for_each(v.begin(), v.end(), [&evenCount] (int n) {
      cout << n;
      if (n % 2 == 0) {
         cout << " ist gerade " << endl;
         ++evenCount;
      } else {
         cout << " ist ungerade " << endl;
      }
   });

   // Gib die Anzahl der geraden Zahlen in der Konsole aus.
   cout << "Es gibt " << evenCount 
        << " gerade Zahlen im Vektor." << endl;
}

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