Erasing an iterator in a loop

Started by
29 comments, last by Gaiiden 21 years, 2 months ago

typedef vector[int] nums;
typedef vector[int]::iterator num_handle;

// assume this is filled with random numbers
nums my_numbers;
for (num_handle iter=my_numbers.begin(); iter!=my_numbers.end(); ++iter)
    if (*iter == 5)
        my_numbers.erase(iter);
  
This code does not work as well as I intended. In fact it doesn't work at all I know I'm using a vector container in this example but I get the same result using a list container too. I guess erasing the current iterator breaks the pointer chain and when ++iter comes around it points to no where. I need a way to patch that up so I can delete iterators in a loop. Anyone? btw - the [] should be angle brackets I know but, you know... html tags and all... _________________________________________________________________ Drew Sikora A.K.A. Gaiiden ICQ #: 70449988 AOLIM: DarkPylat Blade Edge Software Staff Member, GDNet Public Relations, Game Institute 3-time Contributing author, Game Design Methods , Charles River Media Online column - Design Corner at Pixelate Unnoficial IGDA chat! [polaris.starchat.net -> #igda] NJ IGDA Chapter - NJ developers unite!! [Chapter Home | Chapter Forum] "Real programmers don't work from 9 to 5. If any real programmers are around at 9am it's because they were up all night." -Anon. "It's not the size of the source that matters, it's how you use it" - Self

Drew Sikora
Executive Producer
GameDev.net

Advertisement
If I understand what you are trying to do then I can give you the solution I use.

Rather than (VB/Psuedo code)
  For I = Start to Finish     If condition then Remove(I)  Next  

use:
  For I = Finish to Start Step -1     If condition then Remove(I)  Next 

Basically you move backwards in the list, so that when you delete an item it only affects the items you have already passed.


[edited by - michalson on January 18, 2003 7:17:51 PM]
Hmmm, I doubt that would work since you still use the iterator (which would now be invalid) to do the step backwards. Someone posted a good way of doing it (can''t remember who though) like this:

  std::vector<int> my_numbers;for (std::vector<int>::iterator next=my_numbers.begin(),iter=next++ ; iter!=my_numbers.end() ; iter=next++)    if (*iter == 5)        my_numbers.erase(iter);  

this keeps next one step ahead, so it will always have a valid iterator.


Joanus D''Mentia
---------------
Surely 100,000 lemmings couldn''t possibly be wrong!!!
"Voilà! In view, a humble vaudevillian veteran, cast vicariously as both victim and villain by the vicissitudes of Fate. This visage, no mere veneer of vanity, is a vestige of the vox populi, now vacant, vanished. However, this valorous visitation of a bygone vexation stands vivified, and has vowed to vanquish these venal and virulent vermin vanguarding vice and vouchsafing the violently vicious and voracious violation of volition. The only verdict is vengeance; a vendetta held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous. Verily, this vichyssoise of verbiage veers most verbose, so let me simply add that it's my very good honor to meet you and you may call me V.".....V
Inserting or removing elements invalidates reference, pointers, and iterators that refer to the following elements. You must use an algorithm to do this. Try this:

std::vector< int >coll;std::vector< int >::iterator pos;std::list< int >mylist;int value;coll.erase(remove(coll.begin(), coll.end(), val), coll.end());list.remove(bind2nd(equal_to< int >(), value));    

hope this helps


-----------------------------
"There are ones that say they can and there are those who actually do."

"...u can not learn programming in a class, you have to learn it on your own."







[edited by - cMADsc on January 18, 2003 8:06:32 PM]
-----------------------------"There are ones that say they can and there are those who actually do.""...u can not learn programming in a class, you have to learn it on your own."
for (num_handle iter=my_numbers.begin(); iter!=my_numbers.end(); )    if (*iter == 5)        iter = my_numbers.erase(iter);    else        ++iter;   



[edited by - niyaw on January 18, 2003 8:06:55 PM]
You can use either the remove or remove_if algorithms to get rid of the elements you don''t want. They return an iterator to the end of the new sequence. You can use that return value with end() of your container to erase the remaining elements, which have already been copied. Check the documentation to see how the algorithms work.

The only problems I can see with this method is that you don''t have the opportunity to call the deconstructor on removed items, since all the algorithm does it overwrite "bad" values with the good ones.
typedef vector[int] nums;
typedef vector[int]::iterator num_handle

nums my_numbers;
num_handle iter

for (iter=my_numbers.begin();iter!=my_numbers.end();iter++)
{
if(!my_numbers.empty())
{
if (*iter == 5)
{
my_numbers.erase(iter);
}
}
else
{
break;
}
}
Wow, Gaiiden, a GDNet Staff member asking a question. I thought gods didn''t hang out with the lesser people.


tcache
Contact Me
-----------
AH! MY BRAIN IS GOING TO SELF-DETONATE! -- Yours Truly (Jan, 2003)
tcacheContact Me-----------AH! MY BRAIN IS GOING TO SELF-DETONATE! -- Yours Truly (Jan, 2003)
What about:

for (int i=my_numbers.size()-1,i>=0;i--)
{
if (my_numbers(i)==5)
my_numbers.erase(my_numbers.begin()+i);
}

I basically always use integers to loop through vectors. Is this a bad practice?

Edit: replaced angle braquets with parenthesis for my_numbers(i) because of html tags...

[edited by - Floating on January 18, 2003 10:56:50 PM]
quote:I basically always use integers to loop through vectors. Is this a bad practice?

There are lots of algorithms which solve exactly this sort of problem. If you're still writing your own loops it's likely you're making things deliberately difficult for yourself.

cMADsc has the answer. Read, lookup, learn.

[edited by - petewood on January 19, 2003 2:14:08 AM]

This topic is closed to new replies.

Advertisement