|
|
set<>::erase(iterator) question
Usually STL containers have something like "iterator
container<>::erase(iterator)" which erases the element the iterator points
to and returns another valid iterator. Set does not have this, set::erase()
returns void and "invalidates" the iterator.
Now I have the following code:
while(!some_set.empty()) {
for(it = some_set.begin(); it != some_set.end(); it++)
{
...
if (something == true) some_set.erase(it);
...
}
}
And it always worked (using GCC3.2). Now running the same program using the
same test data on another machine (GCC3.3) it is caught in an endless loop.
What could be going on here?
|
|
0
|
|
|
|
Reply
|
harald.grossauer (25)
|
9/23/2003 4:07:54 PM |
|
Harald Grossauer wrote:
> Usually STL containers have something like "iterator
> container<>::erase(iterator)" which erases the element the iterator
> points to and returns another valid iterator. Set does not have this,
> set::erase() returns void and "invalidates" the iterator.
[SNIP]
Get Effective STL from Scott Meyers.
// This is not necessary: while(!some_set.empty()) {
for(it = some_set.begin(); it != some_set.end(); ) // Change
{
...
if (something == true) some_set.erase(it++); // Change
else ++it; // Change
...
}
You need to get the valid iterator *before* the erase runs.
--
WW aka Attila
|
|
0
|
|
|
|
Reply
|
wolof (743)
|
9/23/2003 4:15:53 PM
|
|
"Harald Grossauer" <harald.grossauer@uibk.ac.at> wrote in message news:3f706fb1@sia.uibk.ac.at...
> Usually STL containers have something like "iterator
> container<>::erase(iterator)" which erases the element the iterator points
> to and returns another valid iterator.
That's true for sequences.
> Set does not have this, set::erase() returns void and "invalidates" the iterator.
That's the way associative containers are, unfortuantely. However, the nice thing
is that they only invalidate the erased iterator.
> for(it = some_set.begin(); it != some_set.end(); it++)
> {
> ...
> if (something == true) some_set.erase(it);
> ...
> }
You have two chocies:
1. remember the next iterator somewhere
2. use post increment to accomplish the same thing
next_it = it+1;
if(something == true) some_set.erase(it);
it = next_it;
or
if(something == true) some_set.erase(it++);
else ++it;
|
|
0
|
|
|
|
Reply
|
ron156 (1434)
|
9/23/2003 4:17:42 PM
|
|
WW wrote in <bkprlo$fg3$1@phys-news1.kolumbus.fi>:
> Harald Grossauer wrote:
>> Usually STL containers have something like "iterator
>> container<>::erase(iterator)" which erases the element the iterator
>> points to and returns another valid iterator. Set does not have this,
>> set::erase() returns void and "invalidates" the iterator.
> [SNIP]
>
> Get Effective STL from Scott Meyers.
>
> // This is not necessary: while(!some_set.empty()) {
> for(it = some_set.begin(); it != some_set.end(); ) // Change
> {
> ...
> if (something == true) some_set.erase(it++); // Change
> else ++it; // Change
> ...
> }
>
> You need to get the valid iterator *before* the erase runs.
if i'm not mistaken erase returns the next valid iterator, so:
> for(it = some_set.begin(); it != some_set.end(); ) // Change
> {
> ...
if (something == true)
it = some_set.erase(it++);
...
> }
should do the trick?
--
Groeten keanu,
Jabber ID: knu[at]amessage[dot]de
GPG Key-ID: 0x3246DE81
|
|
0
|
|
|
|
Reply
|
usenet90 (7)
|
9/23/2003 6:10:47 PM
|
|
"keanu" <usenet@keanu.be> wrote in message news:H00cb.36204$_q1.1687695@phobos.telenet-ops.be...
> if i'm not mistaken erase returns the next valid iterator, so:
Yoiu are mistaken. Did you even read the original post? The erase on
associative containers do not, unfortunately, return anything.
>
> > for(it = some_set.begin(); it != some_set.end(); ) // Change
> > {
> > ...
> if (something == true)
> it = some_set.erase(it++);
> ...
> > }
That won't even work on containers where erase DOES return something. It's
undefined behavior in that case. You can do on sequences
if(something)
it = some_sequence.erase(it);
else ++it;
or on associative containers
if(something)
some_set(it++);
else ++it;
|
|
0
|
|
|
|
Reply
|
ron156 (1434)
|
9/23/2003 6:43:49 PM
|
|
keanu wrote:
>
> if i'm not mistaken erase returns the next valid iterator, so:
Not for associative containers. That's sort of the point of the thread.
-Kevin
--
My email address is valid, but changes periodically.
To contact me please use the address from a recent posting.
|
|
0
|
|
|
|
Reply
|
usenet1.spamfree.fusion (961)
|
9/23/2003 6:48:19 PM
|
|
Ron Natalie wrote:
>
>>>for(it = some_set.begin(); it != some_set.end(); ) // Change
>>>{
>>> ...
>>
>> if (something == true)
>> it = some_set.erase(it++);
>> ...
>>
>>>}
>
>
> That won't even work on containers where erase DOES return something. It's
> undefined behavior in that case.
Why is it undefined behavior? The increment is 'finished' before the
function call (sequence point immediately before a function call) and
the assignment occurs after, right?
-Kevin
--
My email address is valid, but changes periodically.
To contact me please use the address from a recent posting.
|
|
0
|
|
|
|
Reply
|
usenet1.spamfree.fusion (961)
|
9/23/2003 6:57:48 PM
|
|
> That won't even work on containers where erase DOES return something.
> It's
> undefined behavior in that case. You can do on sequences
>
> if(something)
> it = some_sequence.erase(it);
> else ++it;
this is what i meant, the ++ was a left over from the copy paste + no sleep
for some reason i thought erase returns the next iterator for every
container
|
|
0
|
|
|
|
Reply
|
usenet90 (7)
|
9/23/2003 7:02:09 PM
|
|
"Kevin Goodsell" <usenet1.spamfree.fusion@neverbox.com> wrote in message news:MI0cb.858$RW4.72@newsread4.news.pas.earthlink.net...
> >> it = some_set.erase(it++);
>
> Why is it undefined behavior? The increment is 'finished' before the
> function call (sequence point immediately before a function call) and
> the assignment occurs after, right?
Yeah, I guess you're right. I was thinking that the side effect could be delayed
but there is an inherent sequence point after the function args are evaluated and
again on return.
|
|
0
|
|
|
|
Reply
|
ron156 (1434)
|
9/23/2003 7:06:33 PM
|
|
Ron Natalie wrote:
> You have two chocies:
> 1. remember the next iterator somewhere
> 2. use post increment to accomplish the same thing
>
> next_it = it+1;
> if(something == true) some_set.erase(it);
> it = next_it;
That's how I did it then. I just thought there might be a "nicer" version
without introducing another "dummy iterator".
>
> or
> if(something == true) some_set.erase(it++);
> else ++it;
|
|
0
|
|
|
|
Reply
|
harald.grossauer (25)
|
9/24/2003 7:31:35 AM
|
|
|
9 Replies
37 Views
(page loaded in 0.124 seconds)
|
|
|
|
|
|
|
|
|