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 :
#include <vector>
#include <iostream>
int main()
{
std::vector<float> v = { 1, 2, 3, 4, 5 };
for (int i = 0; i < 3 && !v.empty(); ++i)
v.pop_back();
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
}
Ausgabe:
1 2
Es ist ein undefiniertes Verhalten , den end()Iterator an die 1-Parameter- erase()Überladung zu übergeben. Selbst wenn dies nicht der erase()Fall wäre, werden Iteratoren ungültig, die sich "an und nach" dem angegebenen Element befinden, und dnach der Iteration der ersten Schleife ungültig.
std::vectorhat eine 2-Parameter- erase()Überladung, die eine Reihe von zu entfernenden Elementen akzeptiert. Sie brauchen überhaupt keine manuelle Schleife:
if (X.size() >= 3)
X.erase(X.end()-3, X.end());
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 mit X.erase(d)dem Programm stürzt ab.
Sofern der Vektor mindestens 3 Elemente enthält, können Sie stattdessen Folgendes tun:
X.erase( X.end() - 3, X.end() );
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 .
Die Definition von end()from cppreference lautet:
Gibt einen Iterator zurück, der auf das Past-the-End-Element im Vektorcontainer verweist.
und etwas darunter:
Es zeigt auf kein Element und darf daher nicht dereferenziert werden.
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.
Sie könnten verwenden reverse_iterator:
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<float> X = {1.1, 2.2, 3.3, 4.4, 5.5, 6.6};
// start the iterator at the last element
vector<float>::reverse_iterator rit = X.rbegin();
// repeat 3 times
for(size_t i = 0; i < 3; i++)
{
rit++;
X.erase(rit.base());
}
// display all elements in vector X
for(float &e: X)
cout << e << '\n';
return 0;
}
Es gibt einige Dinge zu erwähnen:
reverse_iterator ritbeginnt am letzten Element der vector X. Diese Position wird aufgerufen rbegin.eraseerfordert Klassiker, um damit iteratorzu arbeiten. Wir bekommen das ritdurch einen Anruf base. Dieser neue Iterator zeigt jedoch ritin Vorwärtsrichtung auf das nächste Element .ritvor dem Anruf baseund voraneraseAuch wenn Sie mehr darüber erfahren möchten reverse_iterator, empfehle ich Ihnen , diese Antwort zu besuchen .
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 MSVCund clang-clmit dem Standard entweder C++17oder C++14:
#include <iostream>
#include <vector>
int main()
{
std::vector<float> X{ 1.1f, 2.2f, 3.3f, 4.4f, 5.5f, 6.6f };
for (auto f : X) std::cout << f << ' '; std::cout << std::endl;
std::vector<float>::iterator d = X.end();
X.erase(d - 3, d); // This strongly suggest that there IS a "-" operator for a vector iterator!
for (auto f : X) std::cout << f << ' '; std::cout << std::endl;
return 0;
}
Die Definition für operator-lautet wie folgt (in der <vector>Kopfzeile):
_NODISCARD _Vector_iterator operator-(const difference_type _Off) const {
_Vector_iterator _Tmp = *this;
return _Tmp -= _Off;
}
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.
-für diese Arten von Iteratoren definiert sind.
operator-für die Iteratoren keine definiert wären , könnten Sie einfach std::advance()oder std::prev()stattdessen verwenden.
Diese Aussage
if (i == 1) X.erase(d);
hat undefiniertes Verhalten.
Und diese Anweisung versucht, nur das Element vor dem letzten Element zu entfernen
else X.erase(d - i);
weil Sie eine Schleife mit nur zwei Iterationen haben
for (size_t i = 1; i < 3; i++) {
Sie benötigen so etwas wie das Folgende.
#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
int main()
{
std::vector<float> v = { 1, 2, 3, 4, 5 };
auto n = std::min<decltype( v.size() )>( v.size(), 3 );
if ( n ) v.erase( std::prev( std::end( v ), n ), std::end( v ) );
for ( const auto &item : v ) std::cout << item << ' ';
std::cout << '\n';
return 0;
}
Die Programmausgabe ist
1 2
dnicht 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.