STL vector - Iterator vor begin()
-
Hallo zusammen,
ich habe bisher einiges in C++ geschrieben, habe allerdings so gut wie keine Erfahrung mit Iteratoren.
Meine Frage bezieht sich auf die Benutzung von Iteratoren im Zusammenhang mit der vector-Klasse aus der STL.Soweit ich weiß, benutzt diese Random Access Iteratoren, die ja auch dekrementiert werden können. Was passiert nun, wenn ich einen Iterator auf das erste Element in dem Vektor zeigen lasse und ihn anschließend dekrementiere?
iter = vector.begin(); iter--;
Zeigt der Iterator dann immer noch auf begin() oder wird er dadurch ungültig?
Danke schonmal,
Walli.
-
Er zeigt dann vor das erste Element. Man sollte dann natürlich nicht mehr darauf zugreifen, aber ungültig wird er nicht: Wenn du dann nochmal iter++ machst zeigt er wieder auf das erste Element und man kann gültigerweise darauf zugreifen (sofern der Vector nicht leer ist).
-
Das Ergebnis ist AFAIK undefiniert. Visual C++ steigt beim dekrementieren mit
Microsoft Visual Studio C Runtime Library has detected a fatal error
aus.
-
der_Walli schrieb:
...
Er wird dann ungültig. Ein Range geht immer vom ersten Element bis 1 hinter das letzte Element. Alles was außerhalb davon liegt ist undefiniert. Das gilt für alle Container und auch für C-Arrays.
Beispiel:
std::vector<T> vec(...); std::vector<T>::iterator b = vec.begin(); //b zeigt auf das erste Element std::vector<T>::iterator e = vec.end(); //e zeigt eins hinter das letzte Element
Edit: begin()->end()
-
Tachyon schrieb:
Er wird dann ungültig. Ein Range geht immer vom ersten Element bis 1 hinter das letzte Element. Alles was außerhalb davon liegt ist undefiniert. Das gilt für alle Container und auch für C-Arrays.
Und wenn ich ihn danach wieder inkrementiere? Zeigt er dann aufs erste Element (wie SeppJ meinte)?
Tachyon schrieb:
Beispiel:
std::vector<T> vec(...); std::vector<T>::iterator b = vec.begin(); //b zeigt auf das erste Element std::vector<T>::iterator e = vec.begin(); //e zeigt eins hinter das letzte Element
Ich nehme mal an du meintest vec.end()?
-
der_Walli schrieb:
Tachyon schrieb:
Er wird dann ungültig. Ein Range geht immer vom ersten Element bis 1 hinter das letzte Element. Alles was außerhalb davon liegt ist undefiniert. Das gilt für alle Container und auch für C-Arrays.
Und wenn ich ihn danach wieder inkrementiere? Zeigt er dann aufs erste Element (wie SeppJ meinte)?
Tachyon schrieb:
Beispiel:
std::vector<T> vec(...); std::vector<T>::iterator b = vec.begin(); //b zeigt auf das erste Element std::vector<T>::iterator e = vec.begin(); //e zeigt eins hinter das letzte Element
Ich nehme mal an du meintest vec.end()?
Ja, ich meintevec.end()
. Der Iterator wird theoretisch in dem Moment ungültig, in dem Du ihn dekrementierst. Alles weitere was Du dann damit machst ist undefiniert, bis Du Dir wieder einen gültigen Iterator holst.
-
Ich muss mich korrigieren, erst dekrementieren und dann inkrementieren "funktioniert" zwar in der Praxis bei vector::iterator, aber das Verhalten ist standardmäßig doch nicht definiert. Entschuldige die falsche Antwort. Ein Gegenbeispiel das auch in der Praxis nicht funktioniert, wäre ein list::iterator.
-
Ok, danke. Dann weiß ich bescheid.
-
SeppJ schrieb:
Ich muss mich korrigieren, erst dekrementieren und dann inkrementieren "funktioniert" zwar in der Praxis bei vector::iterator, aber das Verhalten ist standardmäßig doch nicht definiert. Entschuldige die falsche Antwort. Ein Gegenbeispiel das auch in der Praxis nicht funktioniert, wäre ein list::iterator.
Liegt daran, dass einem vector::iterator ein simpler Pointer zugrunde liegen kann, der immer dekrementiert werden kann. Wenn jemand den vector::iterator etwas anders implementiert (schwierig, aber nicht unmöglich), dann kann auch da das dekrementieren schief gehn.
Das ist eben das Problem mit undefiniertem Verhalten: man kann durch Ausprobieren nicht zweifelsfrei rausbekommen ob eine Aktion undefiniert ist, weil sie zufälligerweise durchaus funktionieren und ein brauchbares Ergebnis liefern kann.