Iterators

Ein Iterator ist ein Objekt, das Elemente in einem C++-Standardbibliothekscontainer durchlaufen kann und den Zugriff auf einzelne Elemente bereitstellt. Alle C++-Standardbibliothekscontainer stellen Iteratoren bereit, damit Algorithmen standardisiert auf ihre Elemente zugreifen können, ohne dass die Art des Containers von Bedeutung ist, in dem die Elemente gespeichert werden.

Sie können Iteratoren explizit mithilfe von Member- und globalen Funktionen wie begin() und end() Operatoren wie ++ -- z. B. vorwärts oder rückwärts verwenden. Sie können Iteratoren auch implizit mit einer Bereichsschleife oder (für einige Iteratortypen) den Subscript-Operator []verwenden.

In der C++-Standardbibliothek ist der Anfang einer Sequenz oder eines Bereichs das erste Element. Das Ende einer Sequenz oder eines Bereichs wird immer als eins hinter dem letzten Element definiert. Die globalen Funktionen begin und end geben Iteratoren an einen angegebenen Container zurück. Die typische explizite Iteratorschleife durch alle Elemente in einem Container sieht folgendermaßen aus:

vector<int> vec{ 0,1,2,3,4 };
for (auto it = begin(vec); it != end(vec); it++)
{
    // Access element using dereference operator
    cout << *it << " ";
}

Das Gleiche kann einfacher mit einer range-for-Schleife erreicht werden:

for (auto num : vec)
{
    // no dereference operator
    cout << num << " ";
}

Es gibt fünf Kategorien von Iteratoren. Die Kategorien zum Erhöhen der Leistung sind:

  • Ausgabe. Ein Ausgabe-Iterator X kann mithilfe des ++ Operators vorwärts über eine Sequenz durchlaufen und mithilfe des * Operators ein Element nur einmal schreiben.

  • Input. Ein Eingabe-Iterator X kann mithilfe des ++ Operators vorwärts über eine Sequenz durchlaufen und ein Element beliebig oft mithilfe des * Operators lesen. Sie können Eingabe iteratoren mithilfe der == Operatoren != vergleichen. Nachdem Sie eine Kopie eines Eingabe-Iterators erhöht haben, kann keine der anderen Kopien später verglichen, abgeleitet oder erhöht werden.

  • Weiterleiten. Ein Weiterleitungs-Iterator X kann mithilfe des ++-Operators vorwärts über eine Sequenz iterieren und beliebige Elemente lesen oder nicht-const-Elemente beliebig oft mithilfe des * Operators schreiben. Sie können mithilfe des -> Operators auf Elementelemente zugreifen und Weiterleitungs iteratoren mithilfe der == Operatoren und != Operatoren vergleichen. Sie können mehrere Kopien eines Forward-Iterators anfertigen, wobei jede einzelne unabhängig dereferenziert und inkrementiert werden kann. Ein Weiterleitungs iterator, der ohne Verweis auf einen Container initialisiert wird, wird als Null-Weiterleitungs-Iterator bezeichnet. Null-Forward-Iteratoren vergleichen immer gleich.

  • Bidirektional. Ein bidirektionaler Iterator X kann den Platz eines Vorwärts iterators übernehmen. Sie können jedoch auch einen bidirektionalen Iterator wie in --X, oder X--(V = *X--). Sie können auf Elementmitglieder zugreifen und bidirektionale Iteratoren genauso wie Forward-Iteratoren vergleichen.

  • Random Access. Ein Iterator X mit wahlfreiem Zugriff kann den Platz eines bidirektionalen Iterators übernehmen. Mit einem Iterator für zufälligen Zugriff können Sie den Tiefstellungsoperator [] verwenden, um auf Elemente zuzugreifen. Mit den +-+= -= Operatoren können Sie eine bestimmte Anzahl von Elementen vorwärts oder rückwärts bewegen und den Abstand zwischen Iteratoren berechnen. Sie können bidirektionale Iteratoren mithilfe von ==, , !=, <, >, , <=und >=.

Alle Iteratoren können zugewiesen oder kopiert werden. Es wird davon ausgegangen, dass sie einfache Objekte sind und häufig nach Wert übergeben und zurückgegeben werden, nicht nach Verweis. Beachten Sie zudem, dass einer der zuvor beschriebenen Vorgänge eine Ausnahme auslösen kann, wenn er für einen gültigen Iterator ausgeführt wird.

Die Hierarchie der Iteratorkategorien kann durch das Zeigen von drei Sequenzen zusammengefasst werden. Für den schreibgeschützten Zugriff auf eine Sequenz können Sie Folgendes verwenden:

Ausgabe-Iterator
-> Weiterleitungs-Iterator
-> bidirektionale Iterator
-> Iterator für zufälligen Zugriff

Der Nach-rechts-Pfeil bedeutet "kann ersetzt werden durch". Jeder Algorithmus, der einen Ausgabe-Iterator aufruft, sollte z. B. gut mit einem Weiterleitungs iterator funktionieren, aber nicht umgekehrt.

Für den schreibgeschützten Zugriff auf eine Sequenz können Sie Folgendes verwenden:

Eingabe-Iterator
-> Weiterleitungs-Iterator
-> bidirektionale Iterator
-> Iterator für zufälligen Zugriff

In diesem Fall ist ein Eingabeiterator die schwächste aller Kategorien.

Schließlich können Sie für den Lese-/Schreibzugriff auf eine Sequenz Folgendes verwenden:

Weiterleitungs-Iterator
-> bidirektionale Iterator
-> Iterator für zufälligen Zugriff

Ein Objektzeiger kann immer als ein Random-Access-Iterator fungieren. Er kann demnach als eine beliebige Kategorie des Iterators fungieren, wenn er den entsprechenden Lese-/Schreibzugriff auf die Sequenz unterstützt, die er festlegt.

Ein Iterator Iterator, der dem Objektzeiger nicht entspricht, muss zudem die Membertypen definieren, die durch die Spezialisierung iterator_traits<Iterator> erforderlich ist. Diese Anforderungen können erfüllt werden, indem sie vom Iterator der öffentlichen Basisklasse abgeleitet Iterator werden.

Es ist wichtig, die Zusagen und Einschränkungen jeder Iteratorkategorie zu verstehen, um zu sehen, wie Iteratoren von Containern und Algorithmen in der C++-Standardbibliothek verwendet werden.

Hinweis

Sie können die explizite Verwendung von Iteratoren mithilfe von range-for-Schleifen umgehen. Weitere Informationen finden Sie unter Range-based for statement.

Microsoft C++ bietet jetzt überprüfte Iteratoren und Debug-Iteratoren an, um sicherzustellen, dass Sie die Grenzen Ihres Containers nicht überschreiben. Weitere Informationen finden Sie unter Überprüfte Iteratoren und Unterstützung für Iteratordebugging.

Siehe auch

C++-Standardbibliotheksreferenz
Threadsicherheit in der C++-Standardbibliothek