Есть ли лучшая альтернатива std :: remove_if для удаления элементов из вектора?

Задача удаления элементов с определенным свойством из std::vector или другой контейнер подходит для реализации функционального стиля: зачем беспокоиться о циклах, освобождении памяти и правильном перемещении данных?

Однако стандартный способ сделать это в C ++ выглядит следующим образом:

std::vector<int> ints;
...
ints.erase(
std::remove_if(ints.begin(),
ints.end(),
[](int x){return x < 0;}),
ints.end());

В этом примере удаляются все элементы меньше нуля из целочисленного вектора.

Я считаю, что это не только некрасиво, но и легко использовать неправильно. Ясно, что std::remove_if не может изменить размер вектора (как следует из его названия), потому что он получает только итераторы. Но многие разработчики, в том числе и я, не понимают этого с самого начала.

Так есть ли более безопасный и, надеюсь, более элегантный способ добиться этого? Если нет, то почему?

22

Решение

Я считаю, что это не только некрасиво, но и легко использовать неправильно.

Не волнуйтесь, мы все с самого начала.

Ясно, что std :: remove_if не может изменить размер вектора (как следует из его названия), потому что он только передает итераторы. Но многие разработчики, в том числе и я, не понимают этого с самого начала.

Так же. Это смущает всех. Это, вероятно, не следовало называть remove_if все эти годы назад Оглядываясь назад, а?

Так есть ли более безопасный и, надеюсь, более элегантный способ добиться этого?

нет

Если нет, то почему?

Потому что это самый безопасный и элегантный способ сохранения производительности при удалении элементов из контейнера, при котором удаление элемента делает недействительными итераторы.

предвидя:

Что я могу сделать?

Да, обернуть эту идиому в функцию

template<class Container, class F>
auto erase_where(Container& c, F&& f)
{
return c.erase(std::remove_if(c.begin(),
c.end(),
std::forward<F>(f)),
c.end());
}

Призыв в мотивирующем примере становится:

auto is_negative = [](int x){return x < 0;};
erase_where(ints, is_negative);

или же

erase_where(ints, [](int x){return x < 0;});
22

Другие решения

Это станет доступным в C ++ 17-ready компиляторе скоро через std::experimental::erase_if алгоритм:

#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
#include <experimental/vector>

int main()
{
std::vector<int> ints { -1, 0, 1 };
std::experimental::erase_if(ints, [](int x){
return x < 0;
});
std::copy(ints.begin(), ints.end(), std::ostream_iterator<int>(std::cout, ","));
}

Живой пример что печатает 0,1

12

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector