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 d
invalide après la 1ère itération de boucle.
std::vector
a 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 rit
commence au dernier élément du vector X
. Cette position est appeléerbegin
.erase
nécessite un classique iterator
pour travailler avec. Nous obtenons cela rit
en appelant base
. Mais ce nouvel itérateur pointera vers l'élément suivant derit
avant.rit
avant d'appeler base
eterase
Aussi, 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 MSVC
et clang-cl
, avec la norme définie sur C++17
ou 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
d
n'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
.