geek c++ list

list c++ geek



Borrado mientras se itera un std:: list (3)

Si estoy usando un iterator en un bucle for y uso erase en una iteración actual del iterador, ¿el bucle for debería continuar bien y acceder al resto de los elementos de la list ?

Por lo que he leído, este debería ser el caso y es una característica distintiva principal de list vs deque o vector . Para mis propósitos, una queue podría funcionar pero necesito este comportamiento.

Aquí está el bucle que estoy considerando:

std::list<Sequence>::iterator iterator; iterator=m_concurrents.begin(); for (;iterator!=m_concurrents.end();++iterator){ if (iterator->passes()){ m_concurrents.erase(iterator); } }


La forma idiomática de escribir ese bucle sería:

for (auto i = list.begin(); i != list.end();) { if (condition) i = list.erase(i); else ++i; }

Puede hacer lo mismo con un set , multiset , map o multimap . Para estos contenedores, puede borrar un elemento sin afectar la validez de los iteradores a otros elementos. Otros recipientes como el vector o el deque no son tan amables. Para aquellos contenedores, solo los elementos antes del iterador borrado permanecen intactos. Esta diferencia es simplemente porque la list s almacena elementos en nodos asignados individualmente. Es fácil sacar un enlace. vector s son contiguos, sacar un elemento mueve todos los elementos después de que retroceda una posición.

Su bucle está roto porque borra el elemento en i en alguna condición dada. i ya no es un iterador válido después de esa llamada. Tu bucle for entonces incrementa i , pero i no es válido. El infierno sobre la tierra se produce. Esta es la situación exacta por la que el erase devuelve el iterador al elemento después de que se borró ... para que pueda continuar recorriendo la list .

También puedes usar list::remove_if :

list.remove_if([](auto& i) { return i > 10; });

En la lambda, devuelva verdadero si el elemento debe eliminarse. En este ejemplo, eliminaría todos los elementos mayores de 10.


Si solo quiere usarlo para iterador, puede usarlo de esta manera, por ejemplo:

list<int> lst{4, 1, 2, 3, 5}; for(auto it = lst.begin(); it != lst.end();++it){ if ((*it % 2) == 1){ it = lst.erase(it); erase and go to next(erase will return the next iterator) --it; // as it will be add again in for, so we go back one step } } for(auto it:lst)cout<<it<<" "; cout<<endl; //4 2

Pero borrarlo en iterador será más claro:

list<int> lst{4, 1, 2, 3, 5}; auto it = lst.begin(); while (it != lst.end()){ if((*it % 2) == 1){ it = lst.erase(it);// erase and go to next } else{ ++it; // go to next } } for(auto it:lst)cout<<it<<" "; cout<<endl; //4 2

También puede utilizar la función miembro remove_if

list<int> lst{4, 1, 2, 3, 5}; lst.remove_if([](int a){return a % 2 == 1;}); for(auto it:lst)cout<<it<<" "; cout<<endl; //4 2

O use std::remove_if conbine con la función de erase :

list<int> lst{4, 1, 2, 3, 5}; lst.erase(std::remove_if(lst.begin(), lst.end(), [](int a){ return a % 2 == 1; }), lst.end()); for(auto it:lst)cout<<it<<" "; cout<<endl; //4 2

También puede hacer referencia a esta pregunta: ¿ Eliminar un elemento del vector, mientras que en el rango de C ++ 11 ''for'' loop?


for (auto i = list.begin(); i != list.end(); ++i) { if (condition) { list.erase(i); --i; } }