Tengo un código que se ve así:
for (std::list<item*>::iterator i=items.begin();i!=items.end();i++)
{
bool isActive = (*i)->update();
//if (!isActive)
// items.remove(*i);
//else
other_code_involving(*i);
}
items.remove_if(CheckItemNotActive);
Me gustaría eliminar los elementos inactivos inmediatamente después de actualizarlos, para evitar volver a recorrer la lista. Pero si agrego las líneas comentadas, aparece un error cuando llego a i++
: "El iterador de lista no se puede incrementar". Intenté algunas alternativas que no aumentaron en la declaración for, pero no pude hacer que nada funcionara.
¿Cuál es la mejor manera de eliminar elementos mientras recorres una lista estándar?
Respuestas:
Primero debe incrementar el iterador (con i ++) y luego eliminar el elemento anterior (por ejemplo, utilizando el valor devuelto de i ++). Puede cambiar el código a un ciclo while de esta manera:
fuente
i = items.erase(i)
es más seguro, porque es equivalente a una lista, pero seguirá funcionando si alguien cambia el contenedor a un vector. Con un vector, borrar () mueve todo a la izquierda para llenar el agujero. Si intenta eliminar el último elemento con código que incrementa el iterador después de borrar, el final se mueve hacia la izquierda y el iterador se mueve hacia la derecha, más allá del final. Y luego te estrellas.Quieres hacer:
Eso actualizará correctamente el iterador para que apunte a la ubicación después del iterador que eliminó.
fuente
i==items.begin()
?i= items.erase(i);
. Es la forma canónica y ya se encarga de todos esos detalles.Debe hacer la combinación de la respuesta de Kristo y MSN:
Por supuesto, lo más eficiente y más inteligente de SuperCool® STL sería algo como esto:
fuente
Utilice el algoritmo std :: remove_if.
Editar: El trabajo con colecciones debe ser como: 1. preparar la colección. 2. proceso de recogida.
La vida será más fácil si no mezclas estos pasos.
fuente
Aquí hay un ejemplo usando un
for
bucle que itera la lista e incrementa o revalida el iterador en caso de que un elemento sea eliminado durante el recorrido de la lista.fuente
La alternativa para la versión en bucle a la respuesta de Kristo.
Pierde algo de eficiencia, retrocede y luego avanza nuevamente al eliminar, pero a cambio del incremento de iterador adicional, puede hacer que el iterador se declare en el alcance del bucle y que el código se vea un poco más limpio. Qué elegir depende de las prioridades del momento.
La respuesta fue totalmente fuera de tiempo, lo sé ...
fuente
iterator cannot be decremented
Elerase
método necesita arandom access iterator
. Algunas implementaciones de colecciones proporcionan un elementoforward only iterator
que causa la aserción.Lo resumí, aquí está el método tres con ejemplo:
1. usando el
while
bucle2. usando la
remove_if
función miembro en la lista:3. usando la
std::remove_if
función que combina con laerase
función miembro:4. usando el
for
bucle, debería tener en cuenta actualizar el iterador:fuente
La eliminación invalida solo los iteradores que apuntan a los elementos que se eliminan.
Entonces, en este caso, después de eliminar * i, se invalida y no puede hacer un incremento en él.
Lo que puede hacer es primero guardar el iterador del elemento que se va a eliminar, luego incrementar el iterador y luego eliminar el guardado.
fuente
Si piensa en
std::list
una cola, puede quitar y poner en cola todos los elementos que desea conservar, pero solo quitar (y no poner en cola) el elemento que desea eliminar. Aquí hay un ejemplo donde quiero eliminar 5 de una lista que contiene los números 1-10 ...myList
ahora solo tendrá los números 1-4 y 6-10.fuente
Iterar hacia atrás evita el efecto de borrar un elemento en los elementos restantes a atravesar:
PD: vea esto , por ejemplo, con respecto a la iteración hacia atrás.
PS2: no probé a fondo si maneja bien los elementos de borrado en los extremos.
fuente
avoids the effect of erasing an element on the remaining elements
para una lista, probablemente sí. Para un vector tal vez no. Eso no es algo garantizado en colecciones arbitrarias. Por ejemplo, un mapa puede decidir reequilibrarse a sí mismo.Puedes escribir
Puede escribir código equivalente con
std::list::remove_if
, que es menos detallado y más explícitoEl
std::vector::erase
std::remove_if
idioma debe usarse cuando los elementos son un vector en lugar de una lista para mantener la competencia en O (n), o en caso de que escriba un código genérico y los elementos podrían ser un contenedor sin una forma efectiva de borrar elementos individuales (como un vector)fuente
Creo que tienes un error allí, lo codifico de esta manera:
fuente