Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I remove elements from std::list, when I'm iterating on it?

Tags:

c++

stl

Can I remove elements from std::list, when I'm iterating on it? For example so:

std::list<int> lst;
//....
for (std::list<int> itr = lst.begin(); itr != lst.end(); itr++)
{
    if (*itr > 10)
         lst.remove(*itr);
}

? And why?

like image 547
Siarhei Fedartsou Avatar asked Nov 23 '10 21:11

Siarhei Fedartsou


People also ask

Can we remove from list while iterating?

The right way to remove objects from ArrayList while iterating over it is by using the Iterator's remove() method. When you use iterator's remove() method, ConcurrentModfiicationException is not thrown.

How do you remove an element from a list while iterating?

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.

How do you remove an element from a list in C++?

remove() is an inbuilt function in C++ STL which is declared in header file. remove() is used to remove any specific value/element from the list container. It takes the value which is passed as a parameter and removes all the elements with that value from the list container.

How do you remove from a vector while iterating?

To delete single element from a vector using erase() function, pass the iterator of element to it like erase(it). It will delete the element pointed by the iterator the it variable. To delete multiple elements from a vector using erase() function, pass the iterator range to it like erase(start, end-1).


2 Answers

The correct code is the following:

for (std::list<int>::iterator itr = lst.begin(); itr != lst.end(); /*nothing*/)
{
    if (*itr > 10)
        itr = lst.erase(itr);
    else
        ++itr;
}

When you delete an item from the list, you may invalidate the iterator (if it points to the item being deleted.) Therefore you need to delete using erase (which returns a valid iterator pointing to the next item).

Even better idea would be using std::remove_if:

bool greater_than_10(int x)
{
    return x > 10;
}

lst.remove_if(greater_than_10);

If your compiler supports lambdas, you can put it even shorter:

lst.remove_if([](int x){ return x > 10; });

(I didn't test this code, as my compiler is not so new; the lambda function is thankfully stolen from @John Dibling's answer.)


Actually, erasing from list invalidates only the iterators pointing to the item being deleted. Beware however that other STL containers don't have this property.


So, in short: generally speaking, you should not delete the items from the list while iterating through it, because the deletion may invalidate the iterator (and the program will possibly crash). If you are however completely sure that the items which you delete are not the values referenced by any of the iterators which you use at the moment of deletion, you may delete.

Beware that for the other STL containers (e.g. vectors) the constraint is even more strict: deleting from the container invalidates not only iterators pointing to the deleted item, but possibly other iterators, too! So deleting from that containers while iterating through them is even more problematic.

like image 124
Vlad Avatar answered Sep 27 '22 15:09

Vlad


No. The example code invalidates itr, causing undefined behavior. But this would work:

for (std::list<int>::iterator itr = lst.begin(); itr != lst.end(); )
{
    if (*itr > 10)
        itr = lst.erase(itr);
    else
        ++itr;
}
like image 30
aschepler Avatar answered Sep 27 '22 15:09

aschepler