Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Erasing while iterating an std::list

Tags:

If I'm using an iterator in a for loop and I use erase on a current iteration of iterator, the for loop should continue fine and access the rest of the list elements?

From what I have read, this should be the case and is a primary distinguishing characteristic of list vs deque or vector. For my purposes, a queue might work but I need this behavior.

Here is the loop I am considering:

    std::list<Sequence>::iterator iterator;     iterator=m_concurrents.begin();     for (;iterator!=m_concurrents.end();++iterator){         if (iterator->passes()){             m_concurrents.erase(iterator);         }     } 
like image 679
johnbakers Avatar asked Apr 29 '13 00:04

johnbakers


People also ask

Can we remove element from list while iterating?

Even though java. util. ArrayList provides the remove() methods, like remove (int index) and remove (Object element), you cannot use them to remove items while iterating over ArrayList in Java because they will throw ConcurrentModificationException if called during iteration.

How do you remove from list iterator?

An element can be removed from a Collection using the Iterator method remove(). This method removes the current element in the Collection. If the remove() method is not preceded by the next() method, then the exception IllegalStateException is thrown.

How do you remove an element from a list in a while loop?

If you want to delete elements from a list while iterating, use a while-loop so you can alter the current index and end index after each deletion.


1 Answers

The idiomatic way to write that loop would be:

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

You can do the same thing with a set, multiset, map, or multimap. For these containers you can erase an element without affecting the validity to any iterators to other elements. Other containers like vector or deque are not so kind. For those containers only elements before the erased iterator remain untouched. This difference is simply because lists store elements in individually allocated nodes. It's easy to take one link out. vectors are contiguous, taking one element out moves all elements after it back one position.

Your loop is broken because you erase the element at i on some given condition. i is no longer a valid iterator after that call. Your for loop then increments i, but i is not valid. Hell upon earth ensues. This is the exact situation that is why erase returns the iterator to the element after what was erased... so you can continue traversing the list.

You could also use list::remove_if:

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

In the lambda, return true if the element should be removed. In this example, it would remove all elements greater than 10.

like image 139
David Avatar answered Sep 27 '22 20:09

David