2008-09-25 10 views
5

Beim Iterieren über Elemente eines Vektors ist es vorzuziehen, Iteratoren anstelle eines Indexes zu verwenden (siehe Why use iterators instead of array indices?).Erhalte einen Index in einen Vektor mit Iteratoren

std::vector<T> vec; 
std::vector<T>::iterator it; 
for (it = vec.begin(); it != vec.end(); ++it) 
{ 
    // do work 
} 

Es kann jedoch notwendig sein, den Index im Körper der Schleife zu verwenden. Welche der folgenden Situationen wäre in diesem Fall vorzuziehen, wenn man Leistung und Flexibilität/Erweiterbarkeit berücksichtigt?

  1. Revert an den indexierten Schleife
     
    std::vector vec; 
    size_t i; 
    for (i = 0; i < vec.size(); ++i) 
    { 
        // use i 
    } 
    
  2. berechnen Offset
     
    std::vector vec; 
    std::vector::iterator it; 
    for (it = vec.begin(); it != vec.end(); ++it) 
    { 
        size_t i = it - vec.begin(); 
        // use i 
    } 
    
  3. Verwendung std :: Abstand
     
    std::vector vec; 
    std::vector::iterator it; 
    for (it = vec.begin(); it != vec.end(); ++it) 
    { 
        size_t i = std::distance(vec.begin(), it); 
        // use i 
    } 
    

Antwort

13

Wenn Sie ausschließlich einen Vektor verwenden möchten, können Sie zurück zur indizierten Schleife wechseln, da diese Ihre Absicht deutlicher vermittelt als die Iteratorschleife. Wenn die Weiterentwicklung Ihres Programms in der Zukunft jedoch zu einem Containerwechsel führen kann, sollten Sie bei den Iteratoren bleiben und std :: distance verwenden, was garantiert mit allen Standard-Iteratoren funktioniert.

8

Verwendung std :: Abstand ist ein bisschen mehr Generika, da es für alle Iteratoren arbeitet, nicht nur Random-Access-Iteratoren. Und es sollte genauso schnell sein wie It - vec.begin() im Fall von Direktzugriffs-Iteratoren.

Es - vec.begin() ist im Grunde Zeigerarithmetik.

4

In die indizierte Schleife zurückkehren.

Grundsätzlich sind in 90% der Fälle Iteratoren überlegen, dies ist einer dieser 10%. Indem Sie einen Iterator verwenden, machen Sie den Code komplexer und daher schwerer zu verstehen, wenn der Grund für die Verwendung des Iterators überhaupt darin bestand, Ihren Code zu vereinfachen.

+0

Vergessen zu erwähnen Leistung, im Allgemeinen ist es sicher anzunehmen, dass die indexierte Schleife eine bessere Leistung hätte, aber die Leistung wäre in beiden Fällen sehr ähnlich. – Guvante

+0

Ich kann nicht sagen, ich stimme zu. Der Hauptteil der Schleife kann anderen Code enthalten, der den Iterator dereferenziert. Iteratoren sollen Ihren Code nicht einfacher machen, sie machen Ihren Code generischer. Wenn Sie die Iteratoren verwenden, können Sie den Vektor gegen eine Liste austauschen und er würde immer noch funktionieren. – QBziZ

+0

Auch std :: map oder std :: set Iteratoren sind alles andere als dumm. Wenn ich alle möglichen Schlüssel durchlaufen würde, würde es wahrscheinlich ewig dauern. Außerdem müsste ich einen O (log (n)) Lookup für jeden Schlüssel durchführen. Also würde meine Schleife O (m * log (n)) dauern. Mit einem Iterator konnte ich die Sammlung in O (n) Zeit durchlaufen. –

1

Ihnen fehlt eine Lösung: Halten Sie einen Index für den Fall, dass Sie ihn brauchen, aber verwenden Sie ihn nicht als Schleifenbedingung. Funktioniert auch auf Listen, und die Kosten (pro Schleife) sind O (n) und ein zusätzliches Register.

0

Ich würde immer dazu neigen, mit Iteratoren aus zukünftigen Entwicklungsgründen zu halten.

Im obigen Beispiel, wenn Sie vielleicht entschieden haben, std :: vector für std :: set zu tauschen (vielleicht benötigten Sie eine eindeutige Sammlung von Elementen), würde die Verwendung von Iteratoren und distance() weiter funktionieren.

Ich bin mir ziemlich sicher, dass alle Leistungsprobleme bis zu dem Punkt vernachlässigt werden, dass es vernachlässigbar ist.

0

Für Vektoren, verwende ich immer die Ganzzahl-Methode. Jeder Index in den Vektor hat die gleiche Geschwindigkeit wie eine Array-Suche. Wenn ich den Wert sehr oft verwende, erstelle ich aus Bequemlichkeit einen Verweis darauf.

Vektoriteratoren können in der Theorie etwas schneller als ein Index sein, da sie Zeigerarithmetik verwenden, um durch die Liste zu iterieren. Normalerweise finde ich jedoch, dass die Lesbarkeit den minimalen Laufzeitunterschied wert ist.

Ich verwende Iteratoren für andere Containertypen und manchmal, wenn Sie die Loop-Variable nicht benötigen. Aber wenn Sie die Loop-Variable benötigen, machen Sie nichts, außer dass Sie Ihre Loop schwieriger schreiben können. (Ich kann nicht auf C++ 0x Auto warten ..)