C ++ STL-Vektoren: Iterator vom Index abrufen?

200

Also habe ich eine Menge Code geschrieben, der über index [] auf Elemente in einem stl-Vektor zugreift, aber jetzt muss ich nur noch einen Teil des Vektors kopieren. Es sieht so aus, als wäre vector.insert(pos, first, last)es die Funktion, die ich will ... außer ich habe nur die ersten und letzten als Ints. Gibt es eine gute Möglichkeit, einen Iterator für diese Werte zu erhalten?

mpen
quelle
1
Siehe auch: stackoverflow.com/q/2152986/365102
Mateen Ulhaq
Wenn ich mich nicht irre, führt keine der Antworten eine Überprüfung der Grenzen durch, was ein Problem sein könnte. Insbesondere sagen std :: advanced-Dokumente, dass das Verhalten undefiniert ist, wenn Sie es verwenden, um die zugrunde liegenden Containergrenzen zu überschreiten.
Martin Pecka

Antworten:

291

Versuche dies:

vector<Type>::iterator nth = v.begin() + index;
dirkgently
quelle
4
Im Allgemeinen können Sie mit STL-Iteratoren dieselbe Arithmetik verwenden wie mit Zeigern. Sie sind so konzipiert, dass sie bei Verwendung von STL-Algorithmen austauschbar sind.
Vincent Robert
17
@ VincentRobert: Anders herum. Zeiger sind gültige Implementierungen von STL-Zufallsiteratoren, der leistungsstärksten Kategorie. Andere, weniger leistungsfähige Kategorien wie Vorwärtsiteratoren unterstützen jedoch nicht dieselbe Arithmetik.
MSalters
6
Ich möchte meine fünf Cent zu dieser Antwort hinzufügen und empfehlenstd::next(v.begin(), index)
stryku
86

Weg von @dirkgently ( v.begin() + index )nett und schnell für Vektoren erwähnt

Aber die meisten generischen Methoden und für Direktzugriffsiteratoren funktionieren auch mit konstanter Zeit. std::advance( v.begin(), index )


Unterschiede in der Verwendung bearbeiten :

std::vector<>::iterator it = ( v.begin() + index );

oder

std::vector<>::iterator it = v.begin();
std::advance( it, index );

nach @litb Notizen hinzugefügt.

Bayda
quelle
Benötigt std :: advanced nicht einen nicht konstanten Iterator als erstes Argument?
GoldPseudo
Sie können std ::
advanced
1
Sie sollten msvc in dieser Hinsicht nicht vertrauen. Es hat eine nicht standardmäßige Erweiterung, die es dazu bringt, solche Dinge zu akzeptieren. Dennoch verhalten sich alle anderen Compiler standardmäßig und lehnen sie ab.
Johannes Schaub - litb
1
Ich denke, das Problem ist Verwirrung über die Bedeutung von "const": progress () funktioniert gerne mit einem const_iterator <T>, einem veränderlichen Iterator, der auf ein const-Element vom Typ T verweist. Es funktioniert nicht mit einem Iteratorobjekt, das selbst const ist (dh "const iterator <T>" oder "iterator <T> const").
j_random_hacker
7
Wenn Sie wissen, dass Sie es mit einem zu tun haben std::vector, macht es keinen Sinn, es zu verwenden std::advance. Es bringt Sie nur dazu zu denken, dass Sie containerunabhängigen Code schreiben (was Sie nicht tun, wenn Sie an Iterator-Invalidierungsregeln, unterschiedliche Laufzeitkomplexitäten und so weiter denken). Der einzige Fall, std::advanceder Sinn macht, ist, wenn Sie selbst eine Vorlage schreiben, die nicht weiß, um welche Art von Iterator es sich handelt.
Frerich Raabe
47

Ebenfalls; auto it = std::next(v.begin(), index);

Update: Benötigt einen C ++ 11x-kompatiblen Compiler

Viktor Sehr
quelle
2
Es ist zu beachten, dass dies der C ++ 11-Weg ist! std :: next entspricht std :: advanced. Die Verwendung dieser Funktionen anstelle von Arithmetik erleichtert das Austauschen von Containertypen erheblich. Funktioniert sogar auf afaik-C-Arrays, genau wie std :: begin und std :: end.
Zoomulator
2
Es sollte auch beachtet werden, dass std :: advanced von einem Idioten entworfen wird, da er eine Referenz als Ausgabe verwendet und nicht den Rückgabewert.
Viktor Sehr
1
für (auto it = begin (c); it! = end (c);
forward
2
Beide haben ihre Verwendung. stda :: advanced ist nützlich, um den vorhandenen Iterator zu ändern. Es ist ein Leistungsproblem in Schleifen. Ich würde es vorziehen, wenn Sie einen Auftrag vergeben, wie Sie vorschlagen. Ich fand es nur ein bisschen hart und behauptete, es sei idiotisch. Beide Funktionen wurden für unterschiedliche Situationen entwickelt, obwohl sie grundsätzlich gleich sind.
Zoomulator
5
@Zoomulator: Wenn das Kopieren Ihres Iterators ein Leistungsproblem darstellt, müssen Sie größere Probleme lösen.
Mooing Duck
8

Oder Sie können verwenden std::advance

vector<int>::iterator i = L.begin();
advance(i, 2);
TimW
quelle
-3

Tatsächlich soll std :: vector bei Bedarf als C-Tab verwendet werden. (Soweit ich weiß, fordert der C ++ - Standard eine Vektorimplementierung an - Ersatz für ein Array in Wikipedia. ) Zum Beispiel ist es meiner Meinung nach völlig legal, dies wie folgt zu tun:

int main()
{

void foo(const char *);

sdt::vector<char> vec;
vec.push_back('h');
vec.push_back('e');
vec.push_back('l');
vec.push_back('l');
vec.push_back('o');
vec.push_back('/0');

foo(&vec[0]);
}

Natürlich darf foo entweder die als Parameter übergebene Adresse nicht kopieren und irgendwo speichern, oder Sie sollten in Ihrem Programm sicherstellen, dass niemals neue Elemente in vec gepusht werden oder dass eine Änderung der Kapazität angefordert wird. Oder Risikosegmentierungsfehler ...

Daher führt es in Ihrem Beispiel zu

vector.insert(pos, &vec[first_index], &vec[last_index]);
yves Baumes
quelle
Ich frage mich, warum sie beschlossen haben, zu Iteratoren zu abstrahieren, wenn sie nur Zeiger sind ... sie "verstecken" diese Fähigkeiten im Wesentlichen.
Mpen
Aus Gründen der Konsistenz? Da es Ihnen ermöglichen würde, Vektorinstanzen für jede andere Art von Container in Ihrem Code so einfach zu entfernen.
Yves Baumes
4
& vec [i] liefert einen Zeiger, der nicht unbedingt mit dem Vektor <> :: iterator kompatibel ist. vec.begin () + i hat immer noch den Vorteil, dass es der Iterator ist, für den Ihre Bibliothek es definiert - einschließlich überprüfter Iteratoren im Debug-Modus. Wenn Sie also keinen Zeiger benötigen (z. B. für E / A), sollten Sie immer Iteratoren bevorzugen.
Sellibitze
@KerrekSB Ab 23.3.6.1 im c ++ - Standardentwurf: "Die Elemente eines Vektors werden zusammenhängend gespeichert. Wenn also v ein Vektor <T, Allocator> ist, wobei T ein anderer Typ als bool ist, gehorcht es der Identität & v [ n] == & v [0] + n für alle 0 <= n <v.size () "
yves Baumes
2
@yvesBaumes: das hat nichts mit Vektoriteratoren zu tun. Es ist jedoch wahr , dass nackte Zeiger sind auch Iteratoren - sie sind einfach nicht Vektor Iteratoren.
Kerrek SB