The correct way to remove elements from an STL vector?

Started by
21 comments, last by MaulingMonkey 18 years, 10 months ago
Quote:Original post by Couvillion
There's an STL algorithm you could use, remove_if:

//Make a functor for the removal criterionstruct isTemporary{  bool operator()(ScreenEntityBase* seb)  {     return (seb->GetFlags() & SCREENENTITY_TEMPORARY) > 0;  }};...vector<ScreenEntityBase*>::iterator chopped_end;chopped_end = remove_if(ScreenEntityList.begin(), ScreenEntityList.end(), isTemporary());ScreenEntityList.erase(chopped_end, ScreenEntityList.end());


Untested, of course.


// functor as beforetemplate <typename Container, typename Predicate>void filter(const Container& c, const Predicate& p) {  c.erase(remove_if(c.begin(), c.end(), p), c.end());}filter(ScreenEntityList, isTemporary());


? :)

Advertisement
Quote:Original post by Zahlman
// functor as beforetemplate <typename Container, typename Predicate>void filter(const Container& c, const Predicate& p) {  c.erase(remove_if(c.begin(), c.end(), p), c.end());}filter(ScreenEntityList, isTemporary());


? :)


Minor issues, you wanna remove const modifier on the Container type parameter other-wise you can only invoke constant member functions which erase isn't [grin] and for genericity of C++ callable entities you wanna remove the constant reference on the Predicate type aswell, throw in some concept checking to prevent types that are not a model of a Sequence from being used and your sorted.
"Hello, I am currently using this loop to remove elements from a vector which meet certain criteria, i.e. they are flagged as temporary."

It doesn't sound like a job for vector in my ears...
Quote:Original post by Anonymous Poster
"Hello, I am currently using this loop to remove elements from a vector which meet certain criteria, i.e. they are flagged as temporary."

It doesn't sound like a job for vector in my ears...
just to clarify, you probably want to be storing stuff in a list.
Quote:Original post by mrmrcoleman
Hello, I am currently using this loop to remove elements from a vector which meet certain criteria, i.e. they are flagged as temporary.

*** Source Snippet Removed ***

This seems to plunge me into am infinite loop. Could somebody please show me the correct way to do this and if possible explain why their's works and why mine doesn't.

Thanks in advance.

Mark Coleman


Functor happy version...

struct releasing_temporary_entity {    bool operator()( ScreenEntityBase * entity ) const {        if ( (entity->GetFlags() & SCREENENTITY_TEMPORARY) > 0 ) {            entity->Release();            return true;        }        return false;    }};ScreenEntityList.erase    ( std::remove_if        ( ScreenEntityList.begin()        , ScreenEntityList.end()        , releasing_temporary_entity()        )    , ScreenEntityList.end()    );


Preforms at O(N) instead of O(N*N).

Yours fails because:

1) you never increment "it"
2) the iterator "it" is invalidated after erasure, along with all iterators after it.
"2) the iterator "it" is invalidated after erasure, along with all iterators after it."

As far as I can see in my cpp-reference, erase() only calls delete for the object that the pointer points to and then clears the pointer.

...and there is an example where you iterate through a vector and delete every object.

Anyway, vectors should not be used for dynamic purposes in this way...
Quote:Original post by Anonymous Poster
"2) the iterator "it" is invalidated after erasure, along with all iterators after it."

As far as I can see in my cpp-reference, erase() only calls delete for the object that the pointer points to and then clears the pointer.


Quote:From SGI's std::vector documentation:
[5] A vector's iterators are invalidated when its memory is reallocated. Additionally, inserting or deleting an element in the middle of a vector invalidates all iterators that point to elements following the insertion or deletion point. 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.


Can't seem to find similar warning in the MSDN. Then again, they don't even have a warning about iterator invalidation on resize() in there either (where I'm looking) so I'm not suprised.

Quote:...and there is an example where you iterate through a vector and delete every object.


It's a bad idea preformance-wise on a vector (not so on a list), but is legal C++ with a defined effect if one sets the iterator to the return of erase() (which was not done) - however, erasing an object at an iterator most definately invalidates iterators pointing to that object. Also note that undefined behavior such as this can include "running just like you'd expect/hope" - but it's still best avoided, as this can also include "launching nuclear missiles at a cow ranch in Alaska".

Quote:Anyway, vectors should not be used for dynamic purposes in this way...


Vectors can work just fine if your requirements include checking an entire range for dying elements - a list is prefered if you're going to do random willy nilly erasures( read: erase() a single element at a time ), but that's not what's happening here. The effects of cache-consistancy may very well make the vector version outpreform the list version, especially with POD types such as pointers, in which relocation of the item is a simple O(1) time algorithm consisting of moving a measly 4 bytes. Calling this sequence of remove_if and erase on a single range is still an O(N) complexity algorithm, just the same as with a list. Doing this with individual erases will be O(N) for lists, O(N*N) for vectors, which is exactly what I'm trying to point out and provide a sound alternative against.
Quote:Original post by snk_kid
Quote:Original post by Zahlman
// functor as beforetemplate <typename Container, typename Predicate>void filter(const Container& c, const Predicate& p) {  c.erase(remove_if(c.begin(), c.end(), p), c.end());}filter(ScreenEntityList, isTemporary());


? :)


Minor issues, you wanna remove const modifier on the Container type parameter other-wise you can only invoke constant member functions which erase isn't [grin] and for genericity of C++ callable entities you wanna remove the constant reference on the Predicate type aswell,


You are of course correct, I didn't think that one through at all ^^; (There are plenty of good reasons for functors to be stateful, and thus mutable as a result of being applied.)

Quote:throw in some concept checking to prevent types that are not a model of a Sequence from being used and your sorted.


And yes, of course, but I don't know how to do this :(
@mrmrcoleman:
If you still decide to do it your way (though it is very slow so I don't recommend it) then might I suggest that you do it backward i.e. from end() to begin() because that will give you a (very) minor speed increase without too much more complexity.
MaulingMonkey: Yep, I assumed that reserve() was used since I always use it when I use vectors. My bad... But if reserve() is not used than it's even more clear that he should use something besides a vector since he wants a dynamic behaviour.

This topic is closed to new replies.

Advertisement