Problème avec std::map::iterator après l'appel à effacer()
//erasing from map
#include <iostream>
#include <map>
using namespace std;
int main ()
{
map<char,int> mymap;
map<char,int>::iterator it(mymap.begin());
//insert some values:
mymap['a']=10;
mymap['b']=20;
mymap['c']=30;
mymap['d']=40;
mymap['e']=50;
mymap['f']=60;
it=mymap.find('a');
mymap.erase (it); //erasing by iterator
//show content:
for (; it != mymap.end(); it++ )
cout << (*it).first << " => " << (*it).second << endl;
return 0;
}
Pourquoi est-ce que donnera une sortie comme
a => 10
b => 20
c => 30
d => 40
e => 50
f => 60
ne devrait pas "a => 10"
être supprimé de toute façon, mais si je déclare it = mymap.begin()
dans la boucle for, tout est parfait. pourquoi?
programme adapté de : http://www.cplusplus.com/reference/stl/map/erase/
Similaire à: stackoverflow.com/q/1038708/176769
OriginalL'auteur Sunny Raj | 2011-01-08
Vous devez vous connecter pour publier un commentaire.
L'effacement d'un élément d'un
map
invalide les itérateurs pointant vers l'élément (après tout ce que l'élément a été supprimé). Vous ne devez pas réutiliser itérateur.Depuis C++11
erase()
renvoie un nouvel itérateur pointant vers l'élément suivant, qui peut être utilisée pour continuer l'itération:Avant C++11, vous devez manuellement l'avance l'itérateur sur l'élément suivant avant la suppression a lieu, par exemple, comme ceci:
Cela fonctionne parce que la post-incrémentation des effets secondaires de
it++
qui se passe avanterase()
supprime l'élément. Car c'est peut-être pas immédiatement évident, le C++11 variante ci-dessus doivent être privilégiées.Ne fonctionne pas avec G++: codepad.org/D2lApTLL . Le problème est que l'
erase()
méthode a été à l'origine en 1998 définie pour revenirvoid
. Autant que je sache, C++03 changé, mais toujours pas pris en charge par g++.Ne devrait pas votre premier extrait de code lire
mymap.erase(++it)
(pré-incrémentation) plutôt que comme un non-non?Qui permettrait de supprimer l'élément en cours, mais l'élément suivant. Et puis, il serait de quitter l'itérateur pointant à l'élément supprimé, de sorte qu'il aurait le même problème que le code en question.
Je suis confus par la phrase. Vous dites "Vous ne devriez pas réutiliser itérateur (OK), ou à l'avance l'itérateur sur l'élément suivant avant la suppression a lieu (pré-incrémentation), par exemple comme ceci" et d'en présenter un exemple avec la post-incrémentation qui est ensuite répété comme un bon exemple de code. Je m'attends à voir un exemple de mauvais code suivant cette phrase.
OriginalL'auteur sth
Appel
erase()
invalide l'itérateur. Dans ce cas, ce qui se passe est l'itérateur points à la valeur résiduelle laissée dans la mémoire (mais ne comptez pas sur ce comportement indéfini!). Réinitialisation de l'itérateur avecit=mymap.begin()
avant la boucle pour les résultats souhaités.http://codepad.org/zVFRtoV5
Cette réponse montre comment faire pour effacer des éléments lors de l'itération sur une
std::map
:Avec
std::map
, la réponse est malheureusement oui. La suppression d'un élément à une restructuration de l'arbre pour maintenir son équilibre, de sorte que vous pouvez même pas compter sur tout le droit de les supprimer l'élément dans son emplacement d'origine comme avec certains autres mst récipients tels questd::list
.Voir qqch post; si vous la post-incrémentation de l'itérateur lorsque vous appelez effacer, votre itérateur reste valable. Assurez-vous juste que dans votre boucle, vous n'avez pas accidentellement incrément de l'itérateur deux fois. @marcog ce n'est pas tout à fait correct. Tandis que les noeuds peuvent être ré-équilibré, leurs adresses dans la mémoire ne change pas; c'est seulement leur gauche/droite/parent pointeurs (au moins pour les arbres rouge-noir). sth la réponse de travaux.
En augmentant deux fois, c'est le problème, vous ne pensez pas. parce que quand je fais ça, la prochaine fois dans la boucle for, il vérifie la condition et encore incréments de l'itérateur. Cela signifie que chaque fois que je supprime un élément-je me passer d'un élément à côté d'elle.
Voir cette réponse pour la bonne façon de faire une itération sur un
std::map
et d'effacer les éléments en même temps.OriginalL'auteur marcog
Cela a à voir avec la façon dont les
map
est mis en œuvre. Disons que c'est un arbre d'une certaine sorte, comme:Lorsque vous
erase()
l'itérateur, vous devez supprimer le nœud de l'arbre et de libérer son espace. Mais jusqu'à ce que l'emplacement de la mémoire est écrasé, le nœud du contenu sont encore en mémoire. C'est pourquoi vous pouvez obtenir non seulement la valeur, mais aussi l'élément suivant dans l'arborescence. Ainsi, votre résultat est complètement prévu.OriginalL'auteur chrisaycock
it
n'est plus valide aprèsmymap.erase(it)
. Cela signifie, il peut faire ce qu'il veut.OriginalL'auteur Oswald
"il" pointe toujours au même endroit, d'effacer n'a pas de mise à jour de l'itérateur par lui-même, vous devez le faire, par la réinitialisation de l'itérateur. En effet, "il" les points à l'ancien emplacement qui a été effacé à partir du vecteur, mais contient encore les anciennes données.
OriginalL'auteur Akhil