Ich habe einen Vektor. Ich muss die letzten 3 Elemente darin löschen. Beschrieb diese Logik. Das Programm stürzt ab. Was könnte der Fehler sein?
vector<float>::iterator d = X.end();
for (size_t i = 1; i < 3; i++) {
if (i == 1) X.erase(d);
else X.erase(d - i);
}
d
nicht wirklich. Es ist der kanarische Wert, der nur verwendet werden kann, um das Ende des Kanars zu findenvector
. Sie können es nicht entfernen. Sobald Sie einen Iterator löschen, ist er verschwunden. Sie können es danach nicht sicher für irgendetwas verwenden, einschließlichd - i
.Antworten:
Wenn der Vektor mindestens 3 Elemente enthält, ist es einfach, die letzten 3 Elemente zu löschen. Verwenden Sie einfach dreimal pop_back :
Ausgabe:
quelle
Es ist ein undefiniertes Verhalten , den
end()
Iterator an die 1-Parameter-erase()
Überladung zu übergeben. Selbst wenn dies nicht dererase()
Fall wäre, werden Iteratoren ungültig, die sich "an und nach" dem angegebenen Element befinden, undd
nach der Iteration der ersten Schleife ungültig.std::vector
hat eine 2-Parameter-erase()
Überladung, die eine Reihe von zu entfernenden Elementen akzeptiert. Sie brauchen überhaupt keine manuelle Schleife:Live-Demo
quelle
Erstens wird
X.end()
kein Iterator an das letzte Element des Vektors zurückgegeben, sondern ein Iterator an das Element hinter dem letzten Element des Vektors. Dies ist ein Element, das der Vektor nicht besitzt. Deshalb versuchen Sie es Löschen Sie es mitX.erase(d)
dem Programm stürzt ab.Sofern der Vektor mindestens 3 Elemente enthält, können Sie stattdessen Folgendes tun:
Was stattdessen zum drittletzten Element geht und jedes Element danach löscht, bis es dazu kommt
X.end()
.BEARBEITEN: Zur Verdeutlichung
X.end()
handelt es sich um einen LegacyRandomAccessIterator , für den eine gültige-
Operation angegeben ist, die einen anderen LegacyRandomAccessIterator zurückgibt .quelle
Die Definition von
end()
from cppreference lautet:und etwas darunter:
Mit anderen Worten, der Vektor hat kein Element, auf das end () zeigt. Indem Sie dieses Nicht-Element durch die erase () -Methode dereferenzieren, ändern Sie möglicherweise den Speicher, der nicht zum Vektor gehört. Daher können von da an hässliche Dinge passieren.
Es ist die übliche C ++ Konvention Intervalle als [low, high) zu beschreiben, mit dem „niedrigen“ Wert enthielt im Intervall und der „hohe“ Wert ausgeschlossen aus dem Intervall.
quelle
Sie könnten verwenden
reverse_iterator
:Es gibt einige Dinge zu erwähnen:
reverse_iterator rit
beginnt am letzten Element dervector X
. Diese Position wird aufgerufenrbegin
.erase
erfordert Klassiker, um damititerator
zu arbeiten. Wir bekommen dasrit
durch einen Anrufbase
. Dieser neue Iterator zeigt jedochrit
in Vorwärtsrichtung auf das nächste Element .rit
vor dem Anrufbase
und voranerase
Auch wenn Sie mehr darüber erfahren möchten
reverse_iterator
, empfehle ich Ihnen , diese Antwort zu besuchen .quelle
In einem Kommentar (jetzt gelöscht) in der Frage heißt es: "Es gibt keinen Operator für einen Iterator." Der folgende Code kompiliert und funktioniert jedoch in beiden
MSVC
undclang-cl
mit dem Standard entwederC++17
oderC++14
:Die Definition für
operator-
lautet wie folgt (in der<vector>
Kopfzeile):Ich bin jedoch sicherlich kein C ++ - Sprachanwalt, und es ist möglich, dass dies eine dieser "gefährlichen" Microsoft-Erweiterungen ist. Es würde mich sehr interessieren, ob dies auf anderen Plattformen / Compilern funktioniert.
quelle
-
für diese Arten von Iteratoren definiert sind.operator-
für die Iteratoren keine definiert wären , könnten Sie einfachstd::advance()
oderstd::prev()
stattdessen verwenden.Diese Aussage
hat undefiniertes Verhalten.
Und diese Anweisung versucht, nur das Element vor dem letzten Element zu entfernen
weil Sie eine Schleife mit nur zwei Iterationen haben
Sie benötigen so etwas wie das Folgende.
Die Programmausgabe ist
quelle