492 Stimmen

Iteration über std::vector: unsigned vs. signed index variable

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

Betrachten Sie diese beiden Codefragmente, wobei das eine gut 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];
}

die Folgendes erzeugt warning: comparison between signed and unsigned integer expressions .

Ich bin neu in der Welt von C++, daher ist die unsigned Variable sieht für mich ein wenig beängstigend aus und ich weiß unsigned Variablen können gefährlich sein, wenn sie nicht richtig verwendet werden, also - ist das richtig?

857voto

Johannes Schaub - litb Punkte 479831

Für die Iteration rückwärts siehe diese Antwort .

Die Iteration in Vorwärtsrichtung ist fast identisch. Ändern Sie einfach die Iteratoren / tauschen Sie Dekrement durch Inkrement. Sie sollten Iteratoren bevorzugen. Einige Leute empfehlen die Verwendung von std::size_t als Typ der Indexvariablen. Dies ist jedoch nicht portabel. Verwenden Sie immer den size_type Typedef des Containers (Während man im vorwärts iterierenden Fall mit einer Konvertierung auskommen könnte, könnte es im rückwärts iterierenden Fall tatsächlich ganz schief gehen, wenn man std::size_t für den Fall std::size_t ist breiter als der Typedef von size_type ):


Verwendung von std::vector

Verwendung von Iteratoren

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

Wichtig ist, dass Sie für Iteratoren, deren Definition Sie nicht kennen, immer die Präfix-Inkrement-Form verwenden. Dadurch wird sichergestellt, dass Ihr Code so generisch wie möglich ist.

Verwendung von Range C++11

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

Verwendung von Indizes

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

Arrays verwenden

Verwendung von Iteratoren

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

Verwendung von Range C++11

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

Verwendung von Indizes

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

Lesen Sie in der rückwärts iterierenden Antwort, welches Problem die sizeof Ansatz jedoch nachgeben kann.

180voto

kratenko Punkte 7012

Vier Jahre sind vergangen, Google gab mir diese Antwort. Mit dem Standard C++11 (alias C++0x ) gibt es eine neue, angenehme Möglichkeit, dies zu tun (um den Preis der Aufhebung der Abwärtskompatibilität): die neue auto Stichwort. Es erspart Ihnen die Mühe, den Typ des zu verwendenden Iterators explizit anzugeben (und damit den Vektortyp zu wiederholen), wenn es (für den Compiler) offensichtlich ist, welcher Typ zu verwenden ist. Mit v Ihr sein vector können Sie etwa so vorgehen:

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 die Iteration über Sammlungen wie Vektoren. Damit entfällt die Notwendigkeit, Dinge zu schreiben, die immer gleich sind:

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

Um es in einem funktionierenden Programm zu sehen, erstellen Sie 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;
}

Wenn Sie diesen Artikel schreiben, kompilieren Sie ihn mit g++ müssen Sie normalerweise ein zusätzliches Flag setzen, damit es mit dem neuen Standard funktioniert:

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

Jetzt können Sie das Beispiel ausführen:

$ ./auto
17
12
23
42

Bitte beachten Sie dass die Anweisungen zum Kompilieren und Ausführen spezifisch sind für gnu c++ Compiler auf Linux sollte das Programm plattform- (und compiler-) unabhängig sein.

43voto

paxos1977 Punkte 143743

In dem speziellen 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 allgemeineren, aber immer noch recht einfachen Fall würde ich mich für den folgenden entscheiden:

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

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

38voto

Polat Tuzla Punkte 1893

Zu der Antwort von Johannes Schaub:

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

Das mag mit einigen Compilern funktionieren, aber nicht mit gcc. Das Problem hier ist die Frage, ob std::vector::iterator ein Typ, eine Variable (Member) oder eine Funktion (Methode) ist. Wir erhalten den folgenden Fehler 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 liegt in der Verwendung des Schlüsselworts "typename", wie gesagt:

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

17voto

Jasper Bekkers Punkte 6545

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

Auch die Iteration über einen Container in C++ erfolgt im Allgemeinen mit Iteratoren etwa so.

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

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

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

Oder Sie verwenden die verschiedenen Iterationsalgorithmen ( std::transform , std::copy , std::fill , std::for_each et cetera).

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