2011-01-08 15 views
14
// 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; 
} 

¿Por qué esto da una salida comoProblema con std :: Mapa :: iterador después de llamar borrado()

a => 10 
b => 20 
c => 30 
d => 40 
e => 50 
f => 60 

no debería "a => 10" se eliminarán de todos modos, pero si me declaro en el it = mymap.begin() de bucle, todo es perfecto. ¿por qué?

programa adaptado de: http://www.cplusplus.com/reference/stl/map/erase/

+0

similares a: http: // stackoverflow.com/q/1038708/176769 – karlphillip

Respuesta

34

Al borrar un elemento de map se invalidan los iteradores que apuntan a ese elemento (después de que se haya eliminado todo ese elemento). No deberías reutilizar ese iterador. En lugar de ello, avanzar en el repetidor al siguiente elemento antes de la eliminación se lleva a cabo, por ejemplo, así:

mymap.erase(it++); 

Un bucle suprimiendo elementos podría tener este aspecto:

it = mymap.begin(); 
while (it != mymap.end()) { 
    if (something) 
     mymap.erase(it++); 
    else 
     it++; 
} 
+0

Similar a: http://stackoverflow.com/questions/1038708/erase-remove-contents-from-the-map-or-any-other-stl-container-while-iterating/1038761#1038761 – karlphillip

+0

No funciona con G ++ : http://codepad.org/D2lApTLL. El problema es que el método 'erase()' fue originalmente en 1998 definido para devolver 'void'. Afaik C++ 03 cambió eso, pero aún no es compatible con g ++. – Notinlist

+0

¿No debería su primer fragmento de código leer 'mymap.erase (++ it)' (pre-incremento) como un no-no? – OlivierD

2

Calling erase() invalida el iterador. En este caso, lo que está sucediendo es que el iterador apunta al valor residual que queda en la memoria (¡pero no confíe en este comportamiento indefinido!). Restablezca el iterador con it=mymap.begin() antes del bucle para obtener los resultados deseados.

http://codepad.org/zVFRtoV5

This answer muestra cómo borrar elementos, mientras que la iteración en una std::map:

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; 
    } 
} 
+0

Entonces, ¿no es posible usar el iterador dentro de un ciclo for y eliminar elementos basados ​​en alguna condición o en otras palabras, si tengo 1000 elementos en un mapa y quiero eliminar elementos que satisfacen una determinada condición definida por el usuario, cada vez que elimino un elemento, ¿debo romper el ciclo y comenzar de nuevo? –

+2

@Sunil Con 'std :: map', la respuesta desafortunadamente es sí. La eliminación de un elemento reestructura el árbol para mantener su equilibrio, por lo que ni siquiera puede confiar en todo a la derecha del elemento eliminado que se encuentra en su ubicación original, como ocurre con otros contenedores estándar, como 'std :: list'. – marcog

+2

@Sunil Vea la publicación de sth; Si incrementa el iterador cuando llama a borrar, su iterador sigue siendo válido. Solo asegúrate de que en tu ciclo for, no aumente accidentalmente el iterador dos veces. @marcog Eso no es exactamente correcto. Mientras que los nodos pueden ser reequilibrados, sus direcciones reales en la memoria no cambian; son solo sus punteros izquierdo/derecho/primario (al menos para árboles rojo-negro). la respuesta de sth funciona. – Dawson

1

Esto tiene que ver con cómo se implementa el map. Digamos que es un árbol de algún tipo, como:

class map_node { 
    char key; 
    int value; 
    map_node* next; 
    ... 
}; 

Cuando erase() el iterador, se quita el nodo del árbol y desasignar su espacio. Pero hasta que se sobrescriba esa ubicación de memoria, los contenidos del nodo todavía están en la memoria. Es por eso que puede obtener no solo el valor, sino también el siguiente elemento en el árbol. Por lo tanto, su resultado es completamente esperado.

0

it ya no es válido después de mymap.erase(it). Esto significa que puede hacer lo que quiera.

0

"it" sigue apuntando a la misma ubicación, borrar no actualiza el iterador por sí mismo, tiene que hacerlo, restableciendo el iterador. En efecto, "eso" apunta a la ubicación anterior que ha sido borrada del vector pero aún contiene los datos antiguos.

Cuestiones relacionadas