c++ linux visual-studio-2005 stl map

c++ - ¿Qué le sucede a un iterador STL después de borrarlo en VS, UNIX/Linux?



visual-studio-2005 map (4)

Por favor considere la siguiente situación:

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

Me parece que en VS2005, después del "borrado", el iterador será igual a end (), de ahí el bloqueo al intentar incrementarlo. ¿Existen realmente diferencias entre los compiladores en el comportamiento presentado aquí? Si es así, ¿qué igual será el iterador después del "borrar" en UNIX / Linux?

Gracias...


Creo que si modificas la colección invalidas tu iterador. No puedes confiar en el comportamiento, como descubriste.


Después de llamar a erase en un iterador en un std::map , se invalida. Esto significa que no puedes usarlo. Intentar utilizarlo (por ejemplo, incrementándolo) no es válido y puede provocar cualquier cosa (incluido un bloqueo). Para un std::map , llamar a erase en un iterador no invalida ningún otro iterador (por ejemplo) después de esta llamada (siempre it no sea T2pS.end() ), será válido:

T2pS.erase( it++ );

Por supuesto, si usa este enfoque, no querrá incrementarlo incondicionalmente en el ciclo for.

Para este ejemplo, sin embargo, ¿por qué molestarse en borrar en el ciclo for? ¿Por qué no simplemente llamar a T2pS.clear () al final del ciclo?

Por otro lado, parece que tienes un puntero sin formato ''a la derecha'' del mapa, pero parece que el mapa posee el objeto apuntado. En este caso, ¿por qué no hacer que la cosa a la derecha del mapa sea un tipo de puntero inteligente, como std :: tr1 :: shared_ptr?

[Por cierto, no veo ningún parámetro de plantilla para map . ¿Ha escrito usted una instanciación específica de std::map como map en el espacio de nombres local?]


Mira esto :

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


Sí, si borras un iterador, ese iterador obtiene un valor singular , lo que significa que ya no pertenece a ningún contenedor. Ya no puede incrementarlo, disminuirlo ni leerlo / escribir en él. La forma correcta de hacer ese ciclo es:

for(map<T, S*>::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; } }

Para contenedores que podrían invalidar otros iteradores cuando borre un iterador, erase devuelve el siguiente iterador válido. Entonces lo haces con

it = T2pS.erase(it)

Así es como funciona para std::vector y std::deque , pero no para std::map o std::set .