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 d
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:
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 rit
beginnt am letzten Element der vector X
. Diese Position wird aufgerufen rbegin
.erase
erfordert Klassiker, um damit iterator
zu arbeiten. Wir bekommen das rit
durch einen Anruf base
. Dieser neue Iterator zeigt jedoch rit
in Vorwärtsrichtung auf das nächste Element .rit
vor dem Anruf base
und voranerase
Auch 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 MSVC
und clang-cl
mit dem Standard entweder C++17
oder 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
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
.