2009-06-19 23 views
14

Tengo un iterador de lista que pasa por una lista y elimina todos los números pares. Puedo usar el iterador de lista para imprimir bien los números, pero no puedo usar remove() de la lista y paso el iterador desreferenciado.List Iterator Remove()

Me di cuenta de que cuando la declaración remove() está en vigor, * itr se corrompe? ¿Alguien puede explicar esto?

#include <iostream> 
#include <list> 

#define MAX 100 

using namespace std; 

int main() 
{ 
    list<int> listA; 
    list<int>::iterator itr; 

    //create list of 0 to 100 
    for(int i=0; i<=MAX; i++) 
     listA.push_back(i); 

    //remove even numbers 
    for(itr = listA.begin(); itr != listA.end(); ++itr) 
    { 
     if (*itr % 2 == 0) 
     { 
      cout << *itr << endl; 
      listA.remove(*itr); //comment this line out and it will print properly 
     } 
    } 
} 

Respuesta

41

Hay algunos problemas con el código anterior. En primer lugar, el remove invalidará cualquier iterador que esté apuntando a los elementos eliminados. Luego continúas usando el iterador. Es difícil decir qué elemento (s) remove se borrará en el caso general (aunque no en el suyo) ya que puede eliminar más de uno.

En segundo lugar, probablemente esté utilizando el método incorrecto. Eliminar repetirá todos los elementos de la lista buscando elementos coincidentes; esto será ineficiente en su caso porque solo hay uno. Parece que debe usar el método erase, probablemente solo desee borrar el elemento en la posición del iterador. Lo bueno de erase es que devuelve un iterador que se encuentra en la siguiente posición válida. La forma idiomática para usarlo es algo como esto:

//remove even numbers 
for(itr = listA.begin(); itr != listA.end();) 
{ 
    if (*itr % 2 == 0) 
    { 
     cout << *itr << endl; 
     itr=listA.erase(itr); 
    } 
    else 
     ++itr; 
} 

Por último, también se puede utilizar remove_if a hacer lo mismo que usted está haciendo:

bool even(int i) { return i % 2 == 0; } 

listA.remove_if(even); 
2

No puede usar un iterador después de eliminar el elemento al que se refiere.

Sin embargo, los iteradores de lista que hacen referencia a elementos no eliminados después de remove() deben seguir siendo válidos.

-1

Dado que los iteradores dependen de la longitud de la estructura que permanezca igual, la mayoría de los iteradores no permiten que se cambie una lista mientras el iterador está en uso. Si desea ir y cambiar la lista, tendrá que usar un bucle independiente del iterador.

+4

Debo señalar que los iteradores de STL no dependen de la longitud de la estructura. Los iteradores con frecuencia le permiten eliminar ciertos elementos, por ejemplo, los iteradores de vectores le permiten eliminar elementos más allá del iterador, y los iteradores de lista le permiten eliminar cualquier cosa no apuntada por el iterador –

0

Podríamos usar algo como esto:

container.erase(it++); 

he intentado en este ejemplo:

int main(){ 

list<int>*a=new list<int>; 
a->push_back(1); 
a->push_back(2); 
a->push_back(3); 

list<int>::iterator I; 

I=a->begin(); ++I; 

a->erase(I++); 
cout<<*I<<endl; 
} 

y se muestra 3, como yo quería. Ahora no sé si esto es válido o uno de los que "a veces funciona y otras no".

EDITAR: Tal vez es debido al compilador. Por ejemplo, el compilador que estoy usando (GNU gcc-g ++) está tratando las listas (std: :) como circulares, es decir, si aumento el iterador después de list-> end() lo pone al principio.

+0

Esto funcionará para los iteradores 'std :: list' porque esos iteradores solo se invalidan cuando se elimina el elemento al que apuntan. Pero esto no funcionará para los iteradores 'std :: vector' porque esos iteradores se invalidan cuando se elimina el elemento al que apuntan o cualquier elemento anterior al que están apuntando. – David