Réponses:
S'il y a au moins 3 éléments dans le vecteur, supprimer les 3 derniers éléments est simple - utilisez simplement pop_back 3 fois:
#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';
}
Production:
1 2
Il est un comportement indéfini de passer l' end()itérateur à la erase()surcharge à 1 paramètre . Même s'il ne l'était pas, erase()invalide les itérateurs qui sont "au niveau et après" l'élément spécifié, ce qui le rend dinvalide après la 1ère itération de boucle.
std::vectora une erase()surcharge à 2 paramètres qui accepte une gamme d'éléments à supprimer. Vous n'avez pas du tout besoin d'une boucle manuelle:
if (X.size() >= 3)
X.erase(X.end()-3, X.end());
Tout d'abord, X.end()ne renvoie pas un itérateur au dernier élément du vecteur, il renvoie plutôt un itérateur à l'élément après le dernier élément du vecteur, qui est un élément que le vecteur ne possède pas réellement, c'est pourquoi lorsque vous essayez de effacez-le avec X.erase(d)le programme plante.
À la place, à condition que le vecteur contienne au moins 3 éléments, vous pouvez effectuer les opérations suivantes:
X.erase( X.end() - 3, X.end() );
Ce qui va à la place à l'avant-dernier élément et efface chaque élément après cela jusqu'à ce qu'il arrive X.end().
EDIT: Juste pour clarifier, X.end()est un LegacyRandomAccessIterator qui est spécifié pour avoir une -opération valide qui renvoie un autre LegacyRandomAccessIterator .
La définition de end()from cppreference est:
Renvoie un itérateur faisant référence à l'élément past-the-end dans le conteneur vectoriel.
et légèrement en dessous:
Il ne pointe vers aucun élément et ne doit donc pas être déréférencé.
En d'autres termes, le vecteur ne contient aucun élément vers lequel pointe () pointe. En déréférençant ce non-élément via la méthode erase (), vous modifiez éventuellement la mémoire qui n'appartient pas au vecteur. Des choses laides peuvent donc arriver à partir de là.
C'est la convention C ++ habituelle de décrire les intervalles comme [bas, haut), avec la valeur "basse" incluse dans l'intervalle et la valeur "haute" exclue de l'intervalle.
Vous pouvez utiliser un 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;
}
Il y a peu de choses à mentionner:
reverse_iterator ritcommence au dernier élément du vector X. Cette position est appeléerbegin .erasenécessite un classique iteratorpour travailler avec. Nous obtenons cela riten appelant base. Mais ce nouvel itérateur pointera vers l'élément suivant derit avant.ritavant d'appeler baseeteraseAussi, si vous voulez en savoir plus reverse_iterator, je vous suggère de visiter cette réponse .
Un commentaire (maintenant supprimé) dans la question a déclaré qu '"il n'y a pas - d'opérateur pour un itérateur". Cependant, le code suivant compile et fonctionne dans les deux MSVCet clang-cl, avec la norme définie sur C++17ou 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;
}
La définition fournie pour le operator-est la suivante (dans l'en- <vector>tête):
_NODISCARD _Vector_iterator operator-(const difference_type _Off) const {
_Vector_iterator _Tmp = *this;
return _Tmp -= _Off;
}
Cependant, je ne suis certainement pas un avocat du langage C ++, et il est possible que ce soit l'une de ces extensions Microsoft «dangereuses». Je serais très intéressé de savoir si cela fonctionne sur d'autres plateformes / compilateurs.
-sont définis pour ces types d'itérateurs.
operator-définition pour les itérateurs, vous pouvez simplement utiliser std::advance()ou à la std::prev()place.
Cette déclaration
if (i == 1) X.erase(d);
a un comportement indéfini.
Et cette déclaration essaie de supprimer uniquement l'élément avant le dernier élément
else X.erase(d - i);
parce que vous avez une boucle avec seulement deux itérations
for (size_t i = 1; i < 3; i++) {
Vous avez besoin de quelque chose comme ce qui suit.
#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;
}
La sortie du programme est
1 2
dn'existe pas vraiment. C'est la valeur canari un-la-fin utilisable uniquement pour trouver la fin de lavector. Vous ne pouvez pas le supprimer. Ensuite, dès que vous effacez un itérateur, il a disparu. Vous ne pouvez pas l'utiliser en toute sécurité par la suite pour quoi que ce soit, y comprisd - i.