How do I remove element pointed to by iterator in a C++ list? why does not this work?
int main()
{
list<int> l;
l.push_back(5);
l.push_back(6);
for(auto &it: l)
{
l.erase(*it);
}
return 0;
}
How do I remove element pointed to by iterator in a C++ list? why does not this work?
int main()
{
list<int> l;
l.push_back(5);
l.push_back(6);
for(auto &it: l)
{
l.erase(*it);
}
return 0;
}
Why
for(auto &it: l){
l.erase(*it);
}
fails to work:
it
is not an iterator. In a range-based for loop, the variable declared before the colon, the range_declaration, will receive an item in the container, an int
in this case. Since it
will receive an int
, auto
will infer a type of int
resulting in
for(int &it: l){
l.erase(*it);
}
and std::list::erase
requires an iterator. I'm assuming the *
is simply the result of a bit of shotgun debugging to see if dereferencing what was believed to be an iterator helped (it wouldn't).
Side note: You cannot remove an item from a container while iterating the container with a range-based for loop. The magic in the background that implements the for loop looks something like
{
auto cur = container.begin() ;
auto end = container.end();
for ( ; cur != end; ++cur)
{
auto val = *cur;
do_stuff
}
}
If in do_stuff
you remove cur
from the container, ++cur
is invalid. Since cur
's not in the container anymore, you can't use it to advance to the next item in the container. std::list
is very permissive in its iterator invalidation rules. Many containers will fail when the cached end
iterator is invalidated.
How to fix:
The given code appears to be trying to empty all the items in the list
. std::list::clear
does that for you with a single function call.
If you want to release a particular element or select elements by value, you should use std::list::remove
or std::list::remove_if
in conjunction with std::list::erase
eg:
l.erase(l.remove(5), l.end()); // remove all elements containing the number 5
if you want to remove the first item, std::list::pop_front
. To remove the last item, std::list::pop_back
. If you want to remove any other element by position, you must have a valid iterator for that position (If you do not already have one, see std::advance
) and then call erase
. Note that if you're having to iterate a lot to find items to remove, std::list
may not be the right container for this job because list
iteration is expensive and quickly eliminates the benefits of cheap insert and removal.
int main()
{
list<int> l;
list<int>::iterator it;
l.push_back(5);
l.push_back(6);
l.push_back(7);
it=l.begin();// points to the first element
l.erase(it);//pass the iterator to the erase method
for(auto i=l.begin();i!=l.end();i++){
cout<<*i<<" ";
}
return 0;
}
lets say you want to erase the first element. Then simply pass the iterator of the list to erase method.
If you wanted do it in loop cpprefenrence has nice example
when an element removed using erase
method, it returns the next iterator
to removed element, if last element end
will return;
std::list<int> l{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
from above list, let's assume you wanted to remove 4 and 5;
below is the way;
std::list<int>::iterator first = l.begin();
std::advance( first, 4 );
auto it = l.erase( first ); // removes 4 and returns iterator to element 5
l.erase( it ) // removes 5;
as others suggested:
for(auto &it: l){ // range based loop, iterating through elements ex: 4, 5, 6
//l.erase(*it);
std::cout << it; // prints 4, 5, 6
}
you need below for loop
to increment iterator
for( auto it = l.begin(); it != l.end(); it++)
{
// do something hear
}
If you use an iterator-based loop, you can use the return value of erase
to update the iterator:
std::list<int> l = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (auto it = l.begin();
it != l.end();
++it)
{
if (*it % 3 == 0)
{
it = l.erase(it);
}
}
for (auto i : l)
{
std::cout << i << std::endl;
}