tags:

views:

247

answers:

3
+7  A: 
bool IsEven (int i) 
{ 
  return (i%2) == 0; 
}

//...

std::vector<int> v;
v.push_back(1);
v.push_back(2);
v.push_back(3);
v.push_back(4);
v.erase(std::remove_if(v.begin(),v.end(),IsEven), v.end()); 
//v now contains 1 and 3
Brian R. Bondy
If my vector is of pointers that need to be freed after they are removed, how would I do this?
garsh0p
@user219847 You could wrap your pointers in a Boost:smart_ptr object.
wheaties
@wheaties: Agree it's much cleaner to work with smart pointers when using STL containers especially.
Brian R. Bondy
in the example, the predicate IsEven could handle freeing the memory that's pointed to... It's a matter of what makes the most sense for the app you're developing... I tend to prefer for_each as its more readable -- for me.
Jason D
@user219847: You could do what wheaties said, you could use boost's ptr_container library, or you could use `std::partition` (See my answer)
Billy ONeal
@Brian R. Bondy: I'm having some trouble with a compilation error. I edited my question above.
garsh0p
user219847: Pls post as a new question I think it's related to it being a member function.
Brian R. Bondy
@garsh0p: You need to use `std::mem_fun` on that.
Billy ONeal
+4  A: 

Same as Brian R. Bondy's answer, but I'd use a functor rather than a function pointer because compilers are better at inlining them:

struct IsEven : public std::unary_function<int, bool>
{
    bool operator()(int i) 
    { 
      return (i%2) == 0; 
    };
}

//...

std::erase(std::remove_if(v.begin(),v.end(),IsEven()), v.end());

EDIT: In response to If my vector is of pointers that need to be freed after they are removed, how would I do this?

struct IsEven : public std::unary_function<int, bool>
{
    bool operator()(int i) 
    { 
      return (i%2) == 0; 
    };
}

struct DeletePointer : public std::unary_function<myPointedType *, void>
{
    void operator()(myPointedType * toDelete)
    {
        delete toDelete;
    };
}

//...

typedef std::vector<something>::iterator Iterator_T;
Iterator_t splitPoint = std::partition(v.begin(),v.end(),IsEven());
std::for_each(v.begin(), splitPoint, DeletePointer());
v.erase(v.begin(), splitPoint);
Billy ONeal
@GMan: Thanks. Fixed :)
Billy ONeal
+8  A: 

The vector's erase() method returns a new iterator that can be used to continue iterating:

std::vecor<MyClass> v = ...;
std::vecor<MyClass>::iterator it = v.begin();
while (it != v.end()) {
  if (some_condition(*it)) {
    it->cleanup(); // or something
    it = v.erase(it);
  }
  else {
    ++it;
  }
}
sth
+1 for actually answering the question, instead of describing a totally different approach. The question specifically said *while iterating through it*
kibibu
Note: absolutely make sure you remember to assign `it` to the iterator returned by erase! Easy to miss, and the code still *looks* ok without it, but it dies horribly.
kibibu
+1 for the same reason as kibibu, but one should prefer algorithm calls over explicit loops.
Billy ONeal