std::remove, std::remove_if
| Definido en el encabezado <algorithm>
|
||
template< class ForwardIt, class T >
ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );
|
(1) | (hasta C++26) (constexpr desde C++20) |
template< class ForwardIt, class T = typename std::iterator_traits
<ForwardIt>::value_type >
constexpr ForwardIt remove( ForwardIt first, ForwardIt last,
const T& value );
|
(desde C++26) | |
template< class ExecutionPolicy, class ForwardIt, class T >
ForwardIt remove( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, const T& value );
|
(2) | (desde C++17) (hasta C++26) |
template< class ExecutionPolicy, class ForwardIt,
class T = typename std::iterator_traits
<ForwardIt>::value_type >
ForwardIt remove( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, const T& value );
|
(desde C++26) | |
template< class ForwardIt, class UnaryPred >
ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPred p );
|
(3) | (constexpr desde C++20) |
template< class ExecutionPolicy, class ForwardIt, class UnaryPred >
ForwardIt remove_if( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, UnaryPred p );
|
(4) | (desde C++17) |
Elimina todos los elementos que satisfacen criterios específicos del rango [first, last) y devuelve un iterador más allá del final para el nuevo final del rango.
value (usando operator==).p devuelve true.policy.true:
|
|
(hasta C++20) |
|
|
(desde C++20) |
|
Si el tipo de valor de |
(hasta C++11) |
|
Si el tipo de |
(desde C++11) |
Explicación
La eliminación se realiza desplazando los elementos en el rango de tal manera que los elementos que no se deben eliminar aparezcan al principio del rango.
- El desplazamiento se realiza mediante copy assignment (until C++11) move assignment (since C++11) .
- La operación de eliminación es estable: el orden relativo de los elementos que no se eliminan permanece igual.
-
La secuencia subyacente de
[first,last)no se acorta mediante la operación de eliminación. Dado result como el iterador devuelto:
-
-
Todos los iteradores en
[result,last)siguen siendo dereferenceable .
-
Todos los iteradores en
|
(desde C++11) |
Parámetros
| first, last | - | el par de iteradores que define el rango de elementos a procesar |
| value | - | el valor de los elementos a eliminar |
| policy | - | la política de ejecución a utilizar |
| p | - |
predicado unario que retorna
true
si el elemento debe ser eliminado.
La expresión
p
(
v
)
debe ser convertible a
bool
para cada argumento
|
| Requisitos de tipo | ||
-
ForwardIt
debe cumplir con los requisitos de
LegacyForwardIterator
.
|
||
-
UnaryPredicate
debe cumplir con los requisitos de
Predicate
.
|
||
Valor de retorno
Iterador pasado por el final para el nuevo rango de valores (si este no es end , entonces apunta a un valor no especificado, y lo mismo hacen los iteradores hacia cualquier valor entre este iterador y end ).
Complejidad
Dado N como std:: distance ( first, last ) :
Excepciones
Las sobrecargas con un parámetro de plantilla llamado
ExecutionPolicy
reportan errores de la siguiente manera:
-
Si la ejecución de una función invocada como parte del algoritmo lanza una excepción y
ExecutionPolicyes uno de los standard policies , std::terminate es llamado. Para cualquier otroExecutionPolicy, el comportamiento está definido por la implementación. - Si el algoritmo falla al asignar memoria, std::bad_alloc es lanzado.
Implementación posible
| remove (1) |
|---|
template<class ForwardIt, class T = typename std::iterator_traits<ForwardIt>::value_type> ForwardIt remove(ForwardIt first, ForwardIt last, const T& value) { first = std::find(first, last, value); if (first != last) for (ForwardIt i = first; ++i != last;) if (!(*i == value)) *first++ = std::move(*i); return first; } |
| remove_if (3) |
template<class ForwardIt, class UnaryPred> ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPred p) { first = std::find_if(first, last, p); if (first != last) for (ForwardIt i = first; ++i != last;) if (!p(*i)) *first++ = std::move(*i); return first; } |
Notas
Una llamada a
remove
normalmente es seguida por una llamada a la función miembro
erase
del contenedor para eliminar realmente los elementos del contenedor. Estas dos invocaciones juntas constituyen el denominado
erase-remove idiom
.
|
El mismo efecto también puede lograrse mediante las siguientes funciones no miembro:
|
(desde C++20) |
Las funciones miembro de contenedores con nombres similares member functions list::remove , list::remove_if , forward_list::remove , y forward_list::remove_if eliminan los elementos removidos.
Estos algoritmos no pueden utilizarse con contenedores asociativos como std::set y std::map porque sus tipos de iterador no se desreferencian a tipos MoveAssignable (las claves en estos contenedores no son modificables).
La biblioteca estándar también define una sobrecarga de std::remove en <cstdio> , que toma un const char * y se utiliza para eliminar archivos.
Debido a que
std::remove
toma el
value
por referencia, puede tener un comportamiento inesperado si es una referencia a un elemento del rango
[
first
,
last
)
.
| Macro de prueba de características | Valor | Std | Característica |
|---|---|---|---|
__cpp_lib_algorithm_default_value_type
|
202403
|
(C++26) | Inicialización de lista para algoritmos ( 1,2 ) |
Ejemplo
El siguiente código elimina todos los espacios de una cadena desplazando todos los caracteres que no son espacios hacia la izquierda y luego borrando los sobrantes. Este es un ejemplo del erase-remove idiom .
#include <algorithm> #include <cassert> #include <cctype> #include <complex> #include <iomanip> #include <iostream> #include <string> #include <string_view> #include <vector> int main() { std::string str1{"Quick Red Dog"}; std::cout << "1) " << std::quoted(str1) << '\n'; const auto noSpaceEnd = std::remove(str1.begin(), str1.end(), ' '); std::cout << "2) " << std::quoted(str1) << '\n'; // The spaces are removed from the string only logically. // Note, we use view, the original string is still not shrunk: std::cout << "3) " << std::quoted(std::string_view(str1.begin(), noSpaceEnd)) << ", size: " << str1.size() << '\n'; str1.erase(noSpaceEnd, str1.end()); // The spaces are removed from the string physically. std::cout << "4) " << std::quoted(str1) << ", size: " << str1.size() << '\n'; std::string str2 = "Jumped\n Over\tA\vLazy \t Fox\r\n"; str2.erase(std::remove_if(str2.begin(), str2.end(), [](unsigned char x) { return std::isspace(x); }), str2.end()); std::cout << "5) " << std::quoted(str2) << '\n'; std::vector<std::complex<double>> nums{{2, 2}, {1, 3}, {4, 8}}; #ifdef __cpp_lib_algorithm_default_value_type nums.erase(std::remove(nums.begin(), nums.end(), {1, 3}), nums.end()); #else nums.erase(std::remove(nums.begin(), nums.end(), std::complex<double>{1, 3}), nums.end()); #endif assert((nums == std::vector<std::complex<double>>{{2, 2}, {4, 8}})); }
Salida:
1) "Quick Red Dog" 2) "QuickRedDog Dog" 3) "QuickRedDog", size: 15 4) "QuickRedDog", size: 11 5) "JumpedOverALazyFox"
Informes de defectos
Los siguientes informes de defectos que modifican el comportamiento se aplicaron retroactivamente a los estándares de C++ publicados anteriormente.
| DR | Aplicado a | Comportamiento publicado | Comportamiento correcto |
|---|---|---|---|
| LWG 283 | C++98 |
T
se requería que fuera
EqualityComparable
, pero
el tipo de valor de
ForwardIt
no siempre es
T
|
se requiere que el tipo de valor de
ForwardIt
sea CopyAssignable en su lugar |
Véase también
| copia un rango de elementos omitiendo aquellos que satisfacen criterios específicos (plantilla de función & objeto de función de algoritmo) | |
(C++20)(C++20) |
|
| elimina elementos duplicados consecutivos en un rango (plantilla de función & objeto de función de algoritmo) | |
(C++20) |
|
(C++20)(C++20) |
elimina elementos que satisfacen criterios específicos (objeto de función de algoritmo) |