Deleting raw pointers from std::vector

  • A+

I have following pattern:

  1. I have a std::vector containing raw pointers to objects (I know raw pointers are "evil", but it's legacy software needing to be maintained).
  2. Now for each element in the vector I need to do a test and if the test is positive do something with the pointer, delete it and then remove it from the vector:

Pseudo code:

for each pointer in vector {   if (SomeTest(pointer))   {      DoSomething(pointer)      delete pointer      remove pointer from vector   } } 

I'm unable to come up with some nice clean code for this.

This link provides different approaches, but they all look more or less cumbersome to me.

Cumbersome solution I'm using now:

for(auto &  p : v) {    if (SomeTest(p))    {        DoSomething(p);        delete p;        p = nullptr;    } }  v.erase(std::remove(v.begin(), v.end(), nullptr), v.end()); 


As often the answer is: know your <algorithm>s (and is a good reminder to myself) ;)

std::partition is what you're looking for: std::partition(begin, end, p) "moves" the elements of the range [begin, end) which do not satisfy the predicate p at the end of the range; you can then treat them as a batch.

auto const to_be_removed = std::partition(begin(v), end(v), [](auto p){ /* predicate */ }); std::for_each(to_be_removed, end(v), [](auto p) {     /* crunch */     delete p; }); v.erase(to_be_removed, end(v)); 

Full program

#include <iostream> #include <algorithm> #include <vector>  int main() {     std::vector v = { new int{0}, new int{1}, new int{2} };      // let's delete all even values     auto const to_be_removed = std::partition(begin(v), end(v), [](auto p){ return *p % 2 != 0; });     std::for_each(to_be_removed, end(v), [](auto p) {         std::cout << "Deleting value " << *p << ".../n";         delete p;     });     v.erase(to_be_removed, end(v)); } 

Live demo

To go further

This implementation has two major drawbacks: the order from the vector is not stable (1), it could be factored into a reusable function.

  • (1) is solved by std::stable_partition.
  • (2) is not that hard:
template<class InputIt, class UnaryPredicate, class UnaryDeleter> InputIt delete_if(InputIt begin, InputIt end, UnaryPredicate p, UnaryDeleter d) {     auto const to_be_removed = std::stable_partition(begin, end, std::not_fn(p));     std::for_each(to_be_removed, end, [d](auto p) { d(p) ; delete p; });     return to_be_removed; }  template<class Container, class UnaryPredicate, class UnaryDeleter> auto delete_if(Container& c, UnaryPredicate p, UnaryDeleter d) {     using std::begin, std::end;     return c.erase(delete_if(begin(c), end(c), p, d), end(c)); } 


delete_if(v, SomeTest, DoSomething); 

Live demo


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: