Как часто ответ таков: знайте свои <algorithm>
s (и это хорошее напоминание для меня);)
std::partition
- это то, что вы ищете: std::partition(begin, end, p)
«перемещает» элементы диапазона [begin
, end
), которые не удовлетворяют предикату p
в конце диапазона;затем вы можете рассматривать их как пакет.
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));
Полная программа
#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));
}
Живая демоверсия
Чтобы пойти дальше
Эта реализация имеет два основных недостатка: порядок из вектора нестабилен (1), он может быть преобразован в функцию многократного использования (2).
- (1) решена
std::stable_partition
. - (2) не так сложно:
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 демо