Erase elements correctly when traverse a vector?

Started by
13 comments, last by GameDev.net 17 years, 4 months ago
I’m currently porting from VS 2003 to 2005 and I find that it behaves different in some contents. In the code (below) I got run time errors. How do I make it right? I think the iterator get out of range.
for(itrForward = vecActiveLights.begin(); itrForward != vecActiveLights.end(); itrForward++)
{
	if(bCondition)
	{
		// Do some computation
		itrForward = vecActiveLights.erase(itrForward);
	}
}
Thanks
Advertisement
what you have is almost correct.

for this i find it more intuitive to use a while loop

itrForward = vecActiveLights.begin();while( itrForward != vecActiveLights.end() ){	if(bCondition)	{		// Do some computation		itrForward = vecActiveLights.erase(itrForward);	}	else	{		++itrForward;	}}


when the "itrForward = vecActiveLights.erase(itrForward);" line is executed you are not supposed to increment the iterator (which is what happens with your current implementation).

the erase() method returns the _next_ iterator in the sequence, not the current.

-me
Palidine is correct in what he says, but I would prefer this method or just plain std::swap and deferencing the iters.
itrForward = vecActiveLights.begin();while( itrForward != vecActiveLights.end() ){	if(bCondition)	{		// Do some computation		std::iter_swap(itrForward,vecActiveLights.end()-1);		vecActiveLights.pop_back();	}	else	{		++itrForward;	}}
AP, what happens when the swap does nothing (i.e. bCondition is true for the last element in the array). Doesn't the pop_back method then invalidate the itrForward iterator?

Otherwise, yea, a swap -> pop_back will end up being faster in the case of a vector b/c it won't invoke a memcpy to collapse the array.

-me
Good question Palidine, thats what I get for copy and pasting your code.
Would it invalidate it or would it be equal to the end iter? hmm
Yeah, might just be equal to end. From the SGI STL site:

Quote:
It follows that you can prevent a vector's iterators from being invalidated if you use reserve() to preallocate as much memory as the vector will ever use, and if all insertions and deletions are at the vector's end.


So since this is a deletion at the end that would suggest that the iterator is perhaps fine. I'm not sure of the inner workings of iterators, but in a vector i'd assume there is just some pointer offset stuff going on. Assuming .end() is sizeof(T) greater than the last valid element, should be ok. Don't know how your method would fare if the container being iterated were not a vector though...

*goes to learn more about STL =)

-me
Thanks guys :) Palidines suggestion worked just fine. But I didn’t manage to get the other one to work; wouldn't I need to set the itrForward focus somehow (after the swap and pop)?
vecActiveLights.erase(std::remove_if(vecActiveLights.begin(), vecActiveLights.end(), ConditionFunctor()), vecActiveLights.end());
Safe, efficient, idiomatic.

Σnigma
Quote:Original post by Enigma
vecActiveLights.erase(std::remove_if(vecActiveLights.begin(), vecActiveLights.end(), ConditionFunctor()), vecActiveLights.end());
Safe, efficient, idiomatic.

Σnigma


So idiomatic that I even wrap it in a function and grumble at the design of <algorithm> a little bit. (Having a function does provide benefit in terms of code duplication in addition to readability: you avoid mentioning .end() twice, and the container three times.)

Oh, and please reconsider your use of Hungarian notation, and declare your for-loop variables in-line. This is modern C++; we have a real type system and fully baked scoping rules now.
I have another question about STL.

When I refer to elements outside the domain of an iterator, for example itrForward+1 when itrForward == vecExample.end(), the application automatically prone and I got error messages. This is a good feature most of the time but I would like to turn that off, can I do that somehow?

This topic is closed to new replies.

Advertisement