Frage

Was ist der richtige Weg über einen Vektor in C von Iterieren ++?

Betrachten Sie diese zwei Codefragmente, dieser funktioniert:

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

und diese:

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

, welche erzeugt warning: comparison between signed and unsigned integer expressions.

Ich bin neu in der Welt der C ++, so die unsigned Variable mir ein bisschen erschreckend aussieht und ich weiß, unsigned Variablen kann gefährlich sein, wenn sie nicht richtig eingesetzt, so - ist das richtig

War es hilfreich?

Lösung

Iterieren rückwärts

Siehe diese Antwort .

Iterieren Vorwärts

Das ist fast identisch. Ändern Sie einfach den Iteratoren / swap durch Erhöhung verringern. Sie sollten Iteratoren bevorzugen. Manche Leute sagen, den Sie als Indexvariablentyp verwenden std::size_t. Das ist jedoch nicht tragbar. Immer die size_type typedef des Behälters verwenden (Während Sie mit nur einem Umsatz in dem Vorwärts Iterieren Fall wegkommen könnten, könnte es tatsächlich schief geht der ganzen Weg in dem Rückwärts Iterieren Fall, wenn std::size_t Verwendung bei std::size_t ist breiter als das, was die typedef von size_type):

Verwendung von std :: vector

Mit Iteratoren

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

Wichtig ist, verwenden Sie immer das Präfix Schritt Formular für Iteratoren, deren Definitionen Sie nicht wissen. Das wird Ihr Code ausgeführt wird so allgemein wie möglich gewährleisten.

Mit Bereich C ++ 11

for(auto const& value: a) {
     /* std::cout << value; ... */

Mit Indizes

for(std::vector<int>::size_type i = 0; i != v.size(); i++) {
    /* std::cout << v[i]; ... */
}

Verwenden von Arrays

Mit Iteratoren

for(element_type* it = a; it != (a + (sizeof a / sizeof *a)); it++) {
    /* std::cout << *it; ... */
}

Mit Bereich C ++ 11

for(auto const& value: a) {
     /* std::cout << value; ... */

Mit Indizes

for(std::size_t i = 0; i != (sizeof a / sizeof *a); i++) {
    /* std::cout << a[i]; ... */
}

Lesen Sie in der Rückwärts Iterieren Antwort, welches Problem des sizeof Ansatz ergeben kann, though.

Andere Tipps

Vier Jahre sind vergangen, Google gab mir diese Antwort. Mit dem Standard C ++ 11 (auch bekannt als C ++ 0x ) gibt es tatsächlich eine neue angenehme Art und Weise, dies zu tun (um den Preis zu brechen abwärts~~POS=TRUNC): das neue auto Schlüsselwort. Es erspart Ihnen den Schmerz, die explizit den Typ des Iterators angeben zu verwenden (die Vektortyp wieder zu wiederholen), wenn es offensichtlich ist (an den Compiler), die Art zu verwenden. Mit v Ihre vector ist, können Sie etwas tun:

for ( auto i = v.begin(); i != v.end(); i++ ) {
    std::cout << *i << std::endl;
}

C ++ 11 geht sogar noch weiter und gibt Ihnen eine spezielle Syntax für wie Vektoren über Sammlungen iterieren. Es beseitigt die Notwendigkeit, Dinge zu schreiben, die sind immer gleich:

for ( auto &i : v ) {
    std::cout << i << std::endl;
}

Um es in einem Arbeitsprogramm zu sehen, baut eine Datei auto.cpp:

#include <vector>
#include <iostream>

int main(void) {
    std::vector<int> v = std::vector<int>();
    v.push_back(17);
    v.push_back(12);
    v.push_back(23);
    v.push_back(42);
    for ( auto &i : v ) {
        std::cout << i << std::endl;
    }
    return 0;
}

Wie dies zu schreiben, wenn Sie kompilieren diese mit g ++ , die Sie normalerweise benötigen sie setzen mit dem neuen Standard zu arbeiten, indem eine zusätzliche Flagge geben:

g++ -std=c++0x -o auto auto.cpp

Nun können Sie das Beispiel ausführen:

$ ./auto
17
12
23
42

Bitte beachten , dass die Anweisungen zum Kompilieren und Ausführen sind spezifisch für Gnu C ++ Compiler auf Linux , sollte das Programm seine Plattform (und Compiler ) unabhängig ist.

Im konkreten Fall in Ihrem Beispiel, würde ich die STL-Algorithmen verwenden, um dies zu erreichen.

#include <numeric> 

sum = std::accumulate( polygon.begin(), polygon.end(), 0 );

Für einen allgemeinere, aber immer noch recht einfachen Fall, würde ich gehen mit:

#include <boost/lambda/lambda.hpp>
#include <boost/lambda/bind.hpp>

using namespace boost::lambda;
std::for_each( polygon.begin(), polygon.end(), sum += _1 );

In Bezug auf Johannes Schaub Antwort:

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

Das kann mit einigen Compiler arbeiten, aber nicht mit gcc. Das Problem hier ist die Frage, ob std :: vector :: iterator ein Typ ist, eine Variable (Mitglied) oder eine Funktion (Methode). Wir erhalten die folgende Fehlermeldung mit gcc:

In member function ‘void MyClass<T>::myMethod()’:
error: expected `;' before ‘it’
error: ‘it’ was not declared in this scope
In member function ‘void MyClass<T>::sort() [with T = MyClass]’:
instantiated from ‘void MyClass<T>::run() [with T = MyClass]’
instantiated from here
dependent-name ‘std::vector<T*,std::allocator<T*> >::iterator’ is parsed as a non-type, but instantiation yields a type
note: say ‘typename std::vector<T*,std::allocator<T*> >::iterator’ if a type is meant

Die Lösung wird unter dem Stichwort ‚Typnamen‘ wie gesagt:

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

Ein Aufruf vector<T>::size() einen Wert vom Typ std::vector<T>::size_type zurückgibt, nicht int, unsigned int oder nicht.

Auch im Allgemeinen Iteration über einen Container in C ++ erfolgt mit Iteratoren , wie diesen.

std::vector<T>::iterator i = polygon.begin();
std::vector<T>::iterator end = polygon.end();

for(; i != end; i++){
    sum += *i;
}

Dabei gilt T die Art der Daten, die Sie in dem Vektor speichern.

oder mit den verschiedenen Iterationsalgorithmen (std::transform, std::copy, std::fill, std::for_each et cetera).

Verwenden size_t:

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

Wikipedia :

  

Die stdlib.h und stddef.h Header-Dateien definieren einen Datentyp namens size_t, die die Größe eines Objekts zu repräsentieren verwendet wird. Bibliotheksfunktionen, die Größen nehmen erwarten, dass sie vom Typ size_t sein, und der Operator sizeof ausgewertet size_t.

     

Die tatsächliche Art der size_t ist plattformabhängig; ein häufiger Fehler ist size_t ist die gleiche wie unsigned int zu übernehmen, die zu Programmierfehlern führen können, insbesondere als 64-Bit-Architekturen weiter verbreitet werden.

ich in der Regel BOOST_FOREACH verwenden:

#include <boost/foreach.hpp>

BOOST_FOREACH( vector_type::value_type& value, v ) {
    // do something with 'value'
}

Es funktioniert auf STL-Containern, Arrays, C-Strings, etc.

Ein wenig Geschichte:

Zur Darstellung, ob eine Zahl negativ ist oder nicht Computer einen ‚Zeichen‘ Bit verwenden. int ist ein signierter Datentyp bedeutet, dass es positive und negative Werte halten kann (etwa -2billion bis 2billion). Unsigned kann nur positive Zahlen speichern (und da es nicht ein wenig auf Metadaten verschwendet es kann mehr speichern: 0 bis etwa 4 Milliarden).

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

Die Warnung Ihr sagt, dass der rechte Operand Ihrer Ungleichheit Anweisung der linken mehr Daten aufnehmen kann dann.

Im Wesentlichen, wenn Sie einen Vektor mit mehr als 2 Milliarden Einträge haben, und Sie verwenden, um eine ganze Zahl zu Index in Sie Überlaufprobleme getroffen werden (wird die int wickeln zurück um auf negative 2000000000).

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

for(auto it=std::begin(polygon); it!=std::end(polygon); ++it) {
  // do something with *it
}

Welche auch bequem für die reverse Iteration

for(auto it=std::end(polygon)-1; it!=std::begin(polygon)-1; --it) {
  // do something with *it
}

In C ++ 11

würde ich allgemeine Algorithmen wie for_each verwenden für die richtige Art von Iterator und Lambda-Ausdruck zu vermeiden suchen zusätzliche genannten Funktionen / Objekte zu vermeiden.

Das kurze „hübsch“ Beispiel für Ihren speziellen Fall (unter der Annahme Polygon ist ein Vektor von ganzen Zahlen):

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

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

Nicht‘vergessen zu sind: Algorithmus und, natürlich, Vektor:)

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

#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

int main() 
{
   // Create a vector object that contains 10 elements.
   vector<int> v;
   for (int i = 1; i < 10; ++i) {
      v.push_back(i);
   }

   // Count the number of even numbers in the vector by 
   // using the for_each function and a lambda.
   int evenCount = 0;
   for_each(v.begin(), v.end(), [&evenCount] (int n) {
      cout << n;
      if (n % 2 == 0) {
         cout << " is even " << endl;
         ++evenCount;
      } else {
         cout << " is odd " << endl;
      }
   });

   // Print the count of even numbers to the console.
   cout << "There are " << evenCount 
        << " even numbers in the vector." << endl;
}
for (vector<int>::iterator it = polygon.begin(); it != polygon.end(); it++)
    sum += *it; 

Die erste ist der Typ korrekt und richtig in etwas engeren Sinne. (Wenn Sie denken, heißt, die Größe kann nie kleiner als Null sein.) Diese Warnung erscheint mir als eine der guten Kandidaten für die ignoriert werden, wenn.

Überlegen Sie, ob Sie überhaupt

iterieren müssen

Die <algorithm> Standard-Header bieten uns Einrichtungen hierfür:

using std::begin;  // allows argument-dependent lookup even
using std::end;    // if the container type is unknown here
auto sum = std::accumulate(begin(polygon), end(polygon), 0);

Weitere Funktionen in der Algorithmus-Bibliothek durchführen allgemeine Aufgaben - stellen Sie sicher wissen, was verfügbar ist, wenn man sich Mühe sparen will

.

Unklar aber wichtiges Detail: Wenn Sie sagen, „für (auto it)“ wie folgt, können Sie eine Kopie des Objekts zu erhalten, nicht das eigentliche Element:

struct Xs{int i} x;
x.i = 0;
vector <Xs> v;
v.push_back(x);
for(auto it : v)
    it.i = 1;         // doesn't change the element v[0]

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

for(auto &it : v)

Wenn Ihr Compiler unterstützt, können Sie einen Bereich verwenden Basis für die Vektorelemente zuzugreifen:

vector<float> vertices{ 1.0, 2.0, 3.0 };

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

Prints: 1 2 3. Beachten Sie, können Sie nicht mit dieser Technik zum Ändern der Elemente des Vektors.

Die beiden Codesegmente arbeiten gleich. Allerdings unsigned int“Route korrekt ist. Unsigned int-Typen verwenden besser in der Instanz mit dem Vektor arbeiten Sie daran. Der Aufruf der Größe () Member-Funktion auf einem Vektor gibt einen ganzzahligen Wert ohne Vorzeichen, so wollen Sie die Variable zu vergleichen „i“ auf einen Wert der eigenen Art.

Auch wenn Sie noch ein wenig unruhig darüber, wie „unsigned int“ sind in Ihrem Code aussieht, versuchen „uint“. Dies ist im Grunde eine verkürzte Version von „unsigned int“ und es funktioniert genau gleich. Sie brauchen auch nicht andere Header enthalten, es zu benutzen.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top