c++ - recorrer - ¿Cómo puedo eliminar elementos de un std:: map con un iterador?
listas c++ (3)
Si tiene un compilador compatible con C ++ 11, aquí hay una manera fácil de hacerlo:
std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
if (ShouldDelete(*itr)) {
itr = myMap.erase(itr);
} else {
++itr;
}
}
La idea es avanzar el iterador desde el inicio del contenedor hasta el final, verificando en cada paso si el par clave / valor actual debe eliminarse. Si es así, eliminamos el elemento iterado utilizando la función de miembro de erase
, que luego devuelve un iterador al siguiente elemento en el mapa. De lo contrario, avanzamos el iterador hacia adelante normalmente.
Si no tiene un compilador compatible con C ++ 11, o si está trabajando con una base de código anterior, las cosas son un poco más complicadas. Antes de C ++ 11, la función miembro de erase
no devolvería un iterador al siguiente elemento en el mapa. Esto significaba que para eliminar un elemento al iterar, necesitarías usar un baile en tres partes:
- Copia el iterador actual.
- Avance el iterador actual al siguiente elemento.
- Llamar
erase
en la copia del antiguo iterador.
Esto se muestra aquí:
std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
if (ShouldDelete(*itr)) {
std::map<K, V>::iterator toErase = itr;
++itr;
myMap.erase(toErase);
} else {
++itr;
}
}
Este proceso fue necesario porque si acaba de llamar a erase
en el iterador, lo invalidaría , lo que significa que operaciones como incrementar y disminuir conducirían a un comportamiento indefinido. El código anterior lo itr
configurando una copia del iterador, avanzando itr
para que esté en el siguiente elemento y luego borre la copia temporal del iterador.
Usando algunos trucos inteligentes, es posible reducir este código a expensas de la legibilidad. El siguiente patrón es común en el código C ++ anterior, pero no es necesario en C ++ 11:
std::map<K, V>::iterator itr = myMap.begin();
while (itr != myMap.end()) {
if (ShouldDelete(*itr)) {
myMap.erase(itr++); // <--- Note the post-increment!
} else {
++itr;
}
}
El uso del operador de incremento posterior aquí es una forma inteligente de hacer una copia del iterador antiguo (recuerde que un operador postfix ++ devuelve una copia del valor del iterador original) mientras avanza el iterador anterior.
Me gustaría recorrer un std::map
y eliminar elementos en función de su contenido. ¿Qué mejor manera de hacerlo?
Esta es una forma simple:
int value_to_delete( 2 );
for( std::map<int, int>::iterator i = mm.begin(); i != mm.end(); ) {
if( i->second != value_to_delete ) {
mm.erase( i++ ); // advance before iterator become invalid
}
else {
++i;
}
}
for(MyMap::iterator it = mymap.begin(); it!=mymap.end(); ) {
if(mycondition(it))
it = mymap.erase(it);
else
it++;
}
editar: parece que esto solo funciona en MSVC
edit2: en c ++ 0x esto funciona para contenedores asociativos también