J'ai un vecteur. J'ai besoin de supprimer les 3 derniers éléments. Décrit cette logique. Le programme se bloque. Quelle pourrait être l'erreur?
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
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
.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:
Production:
la source
Il est un comportement indéfini de passer l'
end()
itérateur à laerase()
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 rendd
invalide après la 1ère itération de boucle.std::vector
a uneerase()
surcharge à 2 paramètres qui accepte une gamme d'éléments à supprimer. Vous n'avez pas du tout besoin d'une boucle manuelle:Démo en direct
la source
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 avecX.erase(d)
le programme plante.À la place, à condition que le vecteur contienne au moins 3 éléments, vous pouvez effectuer les opérations suivantes:
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 source
La définition de
end()
from cppreference est:et légèrement en dessous:
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.
la source
Vous pouvez utiliser un
reverse_iterator
:Il y a peu de choses à mentionner:
reverse_iterator rit
commence au dernier élément duvector X
. Cette position est appeléerbegin
.erase
nécessite un classiqueiterator
pour travailler avec. Nous obtenons celarit
en appelantbase
. Mais ce nouvel itérateur pointera vers l'élément suivant derit
avant.rit
avant d'appelerbase
eterase
Aussi, si vous voulez en savoir plus
reverse_iterator
, je vous suggère de visiter cette réponse .la source
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
etclang-cl
, avec la norme définie surC++17
ouC++14
:La définition fournie pour le
operator-
est la suivante (dans l'en-<vector>
tête):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.
la source
-
sont définis pour ces types d'itérateurs.operator-
définition pour les itérateurs, vous pouvez simplement utiliserstd::advance()
ou à lastd::prev()
place.Cette déclaration
a un comportement indéfini.
Et cette déclaration essaie de supprimer uniquement l'élément avant le dernier élément
parce que vous avez une boucle avec seulement deux itérations
Vous avez besoin de quelque chose comme ce qui suit.
La sortie du programme est
la source