Using std::set::erase with iterators

M

mathieu

Hi,

I do not understand how I am supposed to use erase when looping over
elements in a set, here is what I am trying to do (*). Could someone
please indicate how was I supposed to do it properly ? All I can think
of is something like this (very cumbersome):

if( *it % 2 )
{
std::set<int>::const_iterator duplicate = it;
++it;
s.erase( duplicate );
}
else
{
++it;
}


Thanks
-Mathieu

(*)
#include <set>
#include <iostream>

int main()
{
std::set<int> s;
for(int i =0; i < 10; ++i)
{
s.insert( i );
}

for( std::set<int>::const_iterator it = s.begin(); it != s.end(); +
+it)
{
if( *it % 2 )
s.erase( it );
}

for( std::set<int>::const_iterator it = s.begin(); it != s.end(); +
+it)
{
std::cout << *it << std::endl;
}

return 0;
}
 
O

Ondra Holub

Hi,

I do not understand how I am supposed to use erase when looping over
elements in a set, here is what I am trying to do (*). Could someone
please indicate how was I supposed to do it properly ? All I can think
of is something like this (very cumbersome):

if( *it % 2 )
{
std::set<int>::const_iterator duplicate = it;
++it;
s.erase( duplicate );
}
else
{
++it;
}

Thanks
-Mathieu

(*)
#include <set>
#include <iostream>

int main()
{
std::set<int> s;
for(int i =0; i < 10; ++i)
{
s.insert( i );
}

for( std::set<int>::const_iterator it = s.begin(); it != s.end(); +
+it)
{
if( *it % 2 )
s.erase( it );
}

for( std::set<int>::const_iterator it = s.begin(); it != s.end(); +
+it)
{
std::cout << *it << std::endl;
}

return 0;

}

If you erase some item, iterators become invalid. So you cannot
continue with the cycle driven by invalid iterators.

Use std::remove_if and std::set::erase(std::remove_if(begin, end,
condition), end) instead. (begin and end are range limits in your set)
 
J

James Kanze

I do not understand how I am supposed to use erase when looping over
elements in a set, here is what I am trying to do (*). Could someone
please indicate how was I supposed to do it properly ? All I can think
of is something like this (very cumbersome):
if( *it % 2 )
{
std::set<int>::const_iterator duplicate = it;
++it;
s.erase( duplicate );
}
else
{
++it;
}

That's more or less the solution. You can simplify it a little:

if ( *it % 2 ) {
s.erase( it ++ ) ;
} else {
++ it ;
}

but that's about it. In the next version of the standard
(unless I misread something), you will be able to use the same
algorithm you'd use for the other containers:

if ( *it % 2 != 0 ) {
it = s.erase( it ) ;
} else {
++ it ;
}

Some implementations may support this already.
 
J

James Kanze

[...]
Use std::remove_if and std::set::erase(std::remove_if(begin,
end, condition), end) instead. (begin and end are range limits
in your set)

With std::set? remove_if requires mutating iterators, which
std::set doesn't provide.
 
A

Abhishek Padmanabh

Hi,

  I do not understand how I am supposed to use erase when looping over
elements in a set, here is what I am trying to do (*). Could someone
please indicate how was I supposed to do it properly ? All I can think
of is something like this (very cumbersome):

    if( *it % 2 )
      {
      std::set<int>::const_iterator duplicate = it;
      ++it;
      s.erase( duplicate );
      }
    else
      {
      ++it;
      }

You could use the returned iterator out of the erase call. Like this:

for( std::set<int>::iterator it = s.begin(); it != s.end(); )
{
if( *it % 2 )
it = s.erase( it );
else
++it;
}

std::set is node-base, so erasing an element does not invalidate all
iterators, it just makes the removed item's iterator invalid and so
you cannot advance it with operator++() as your original for-loop is
doing:

for( std::set<int>::const_iterator it = s.begin(); it != s.end(); +
+it)
{
if( *it % 2 )
s.erase( it ); //--->> Here you erase it and then use the same
'it' to advance as ++it.
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,904
Latest member
HealthyVisionsCBDPrice

Latest Threads

Top