Qu’advient-il d’un iterator STL après l’avoir effacé dans VS, UNIX / Linux?

Veuillez considérer le scénario suivant:

map(T,S*) & GetMap(); //Forward decleration map(T, S*) T2pS = GetMap(); for(map(T, S*)::iterator it = T2pS.begin(); it != T2pS.end(); ++it) { if(it->second != NULL) { delete it->second; it->second = NULL; } T2pS.erase(it); //In VS2005, after the erase, we will crash on the ++it of the for loop. //In UNIX, Linux, this doesn't crash. }//for 

Il me semble que dans VS2005, après le “erase”, l’iterator sera égal à end (), d’où le crash en essayant de l’incrémenter. Y a-t-il vraiment des différences entre les compilateurs dans le comportement présenté ici? Si oui, quel sera l’iterator après “effacer” sous UNIX / Linux?

Merci…

Oui, si vous effacez un iterator, cet iterator reçoit une soi-disant valeur singulière , ce qui signifie qu’il n’appartient plus à aucun conteneur. Vous ne pouvez plus incrémenter, décrémenter ou lire / écrire plus. La manière correcte de faire cette boucle est la suivante:

 for(map::iterator it = T2pS.begin(); it != T2pS.end(); T2pS.erase(it++)) { // wilhelmtell in the comments is right: no need to check for NULL. // delete of a NULL pointer is a no-op. if(it->second != NULL) { delete it->second; it->second = NULL; } } 

Pour les conteneurs qui pourraient invalider d’autres iterators lorsque vous effacez un iterator, erase renvoie le prochain iterator valide. Alors tu le fais avec

 it = T2pS.erase(it) 

Cela fonctionne comme ça pour std::vector et std::deque , mais pas pour std::map ou std::set .

Après avoir appelé erase sur un iterator dans un std::map , il est invalidé. Cela signifie que vous ne pouvez pas l’utiliser. Essayer de l’utiliser (par exemple en l’incrémentant) n’est pas valide et peut causer des problèmes (y compris un crash). Pour un std::map , l’appel de l’ erase sur un iterator n’invalide aucun autre iterator (par exemple) après cet appel (tant it ne T2pS.end() pas de T2pS.end() ), il sera valide:

 T2pS.erase( it++ ); 

Bien sûr, si vous utilisez cette approche, vous ne voudrez pas l’incrémenter inconditionnellement dans la boucle for.

Pour cet exemple, cependant, pourquoi s’embêter à effacer dans la boucle for? Pourquoi ne pas simplement appeler T2pS.clear () à la fin de la boucle.

D’un autre côté, il semble que vous ayez un pointeur brut à droite de la carte, mais la carte semble posséder l’object pointé. Dans ce cas, pourquoi ne pas faire de la chose à droite de la carte une sorte de pointeur intelligent, tel que std :: tr1 :: shared_ptr?

[Incidemment, je ne vois aucun paramètre de modèle à map . Avez-vous tapé une instanciation spécifique de std::map tant que map dans l’espace de noms local?]

Voir ceci :

 for (i = v.begin(); i != v.end(); ) { //... if (erase_required) { i = v.erase(i); } else { ++i; } } 

Je pense que si vous modifiez la collection, vous invalidez votre iterator. Vous ne pouvez pas compter sur le comportement, comme vous l’avez découvert.