remove from blank c++ c++11 stl c++17 erase-remove-idiom

c++ - from - ¿Existe una mejor alternativa a std:: remove_if para eliminar elementos de un vector?



erase space from string c++ (2)

Lo encuentro no solo feo sino también fácil de usar incorrectamente.

No te preocupes, todos lo hicimos al principio.

Está claro que std :: remove_if no puede cambiar el tamaño del vector (como sugiere su nombre) porque solo se pasan los iteradores. Pero muchos desarrolladores, incluido yo mismo, no lo entienden al principio.

Mismo. Confunde a todos. Probablemente no debería haber sido llamado remove_if hace remove_if años. En retrospectiva, ¿eh?

Entonces, ¿hay una forma más segura y, con suerte, más elegante de lograr esto?

No

Si no, ¿por qué?

Debido a que esta es la forma más segura y elegante de conservar el rendimiento al eliminar elementos de un contenedor en el que la eliminación de un elemento invalida los iteradores.

anticipando

¿Algo que pueda hacer?

Sí, envuelve este lenguaje en una función

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()); }

La llamada en el ejemplo motivador se convierte entonces en:

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

o

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

La tarea de eliminar elementos con una determinada propiedad de un std::vector u otro contenedor se presta a una implementación de estilo funcional: ¿por qué molestarse con los bucles, la desasignación de memoria y mover los datos correctamente?

Sin embargo, la forma estándar de hacer esto en C ++ parece ser el siguiente idioma:

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

Este ejemplo elimina todos los elementos menos de cero de un vector entero.

Lo encuentro no solo feo sino también fácil de usar incorrectamente. Está claro que std::remove_if no puede cambiar el tamaño del vector (como sugiere su nombre) porque solo se pasan los iteradores. Pero muchos desarrolladores, incluido yo mismo, no lo entienden al principio.

Entonces, ¿hay una forma más segura y, con suerte, más elegante de lograr esto? Si no, ¿por qué?


Esto estará disponible en un compilador listo para C ++ 17 pronto a través del algoritmo en.cppreference.com/w/cpp/experimental/vector/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, ",")); }

Ejemplo vivo que imprime 0,1