std::remove, std::remove_if
| Definido en el archivo de encabezado <algorithm>
|
||
| (1) | ||
template< class ForwardIt, class T > ForwardIt remove( ForwardIt first, ForwardIt last, const T& value ); |
(constexpr desde C++20) (hasta C++26) |
|
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) | |
| (2) | ||
template< class ExecutionPolicy, class ForwardIt, class T > ForwardIt remove( ExecutionPolicy&& policy, ForwardIt first, ForwardIt last, const T& value ); |
(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 un criterio específico del rango [first, last) y devuelve un iterador pasado el final para el nuevo final del rango.
value (usando operator==).p devuelve true.policy.std::is_execution_policy_v<std::decay_t<ExecutionPolicy>> (hasta C++20) std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>> (desde C++20) sea verdadera.
|
Si el tipo valor de |
(hasta C++11) |
|
Si el tipo de |
(desde C++11) |
Explicación
La eliminación se realiza desplazando los elementos del rango de forma que los elementos que no se van a eliminar aparezcan al principio del rango.
- El desplazamiento se realiza mediante la asignación de copia (hasta C++11)asignación de movimiento (desde C++11).
- La operación de eliminación es estable: el orden relativo de los elementos que no se eliminarán permanece igual.
- La secuencia subyacente de
[first,last)no se acorta mediante la operación de eliminación. Dadoresultcomo el iterador devuelto:
- Todos los iteradores en
[result,last)siguen siendo desreferenciables.
- Todos los iteradores en
|
(desde C++11) |
Parámetros
| first, last | - | El rango de elementos a procesar. |
| value | - | El valor de los elementos a eliminar. |
| policy | - | La política de ejecución a usar. Véase política de ejecución para más detalles. |
| p | - | Predicado unario que devuelve true Si el elemento debe ser eliminado.. La expresión |
| Requisitos de tipo | ||
-ForwardIt debe satisfacer los requisitos de ForwardIterator.
| ||
-UnaryPredicate debe satisfacer los requisitos de Predicado.
| ||
Valor de retorno
Iterador pasado del final para el nuevo rango de valores (si éste no es end, entonces apunta a un valor no especificado, al igual que los iteradores a cualquier valor entre este iterador y end).
Complejidad
Dada N como std::distance(first, last):
operator==.p.Excepciones
Las sobrecargas con un parámetro de plantilla llamado ExecutionPolicy (política de ejecución) reportan errores tales que:
- Si la ejecución de una función invocada como parte del algoritmo lanza una excepción y la política de ejecución es una de las tres políticas estándar, se llama a std::terminate. Para cualquier otra política de ejecución, el comportamiento está definido por la implementación.
- Si el algoritmo falla al asignar memoria, se lanza std::bad_alloc.
Posible implementación
| 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 suele ir seguida de una llamada a la función miembro erase de un contenedor para eliminar elementos del contenedor. Estas dos invocaciones juntas constituyen lo que se denomina el modismo borrar-eliminar.
|
El mismo efecto también se puede lograr con las siguientes funciones no miembro:
|
(desde C++20) |
Las funciones miembro de nombre similar, de los contenedores list::remove, list::remove_if, forward_list::remove y forward_list::remove_if borran los elementos eliminados.
Estos algoritmos no se pueden utilizar con contenedores asociativos como std::set y std::map porque sus tipos de iterador no hacen desreferencia a los tipos AsignablePorMovimiento (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 value por referencia, puede tener un comportamiento no esperado si es una referencia a un elemento del rango [first, last).
| Macro de Prueba de característica | Valor | Estándar | Comentario |
|---|---|---|---|
__cpp_lib_algorithm_default_value_type |
202403 |
(C++26) | inicialización por lista para los algoritmos (1,2) |
Ejemplo
El siguiente código elimina todos los espacios de una cadena desplazando todos los caracteres que no son espacios a la izquierda y luego borrando el extra. Esto es un ejemplo del modismo borrar-eliminar.
#include <algorithm>
#include <cassert>
#include <cctype>
#include <complex>
#include <iostream>
#include <string>
#include <string_view>
#include <vector>
int main()
{
std::string str1 {"Texto con algunos espacios"};
auto noSpaceEnd = std::remove(str1.begin(), str1.end(), ' ');
// Los espacios se eliminan de la cadena solo lógicamente.
// Usamos una vista sobre cadena, la cadena original aún no se ha reducido:
std::cout << std::string_view(str1.begin(), noSpaceEnd)
<< " tamaño: " << str1.size() << '\n';
str1.erase(noSpaceEnd, str1.end());
// Los espacios se eliminan de la cadena físicamente.
std::cout << str1 << " tamaño: " << str1.size() << '\n';
std::string str2 = "Texto\n con\talgunos \t espacios en blanco\n\n";
str2.erase(std::remove_if(str2.begin(),
str2.end(),
[](unsigned char x) { return std::isspace(x); }),
str2.end());
std::cout << 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:
Textoconalgunosespacios tamaño: 28
Textoconalgunosespacios tamaño: 23
Textoconalgunosespaciosenblanco
Informes de defectos
Los siguientes informes de defectos de cambio de comportamiento se aplicaron de manera retroactiva a los estándares de C++ publicados anteriormente.
| ID | Aplicado a | Comportamiento según lo publicado | Comportamiento correcto |
|---|---|---|---|
| LWG 283 | C++98 | Se requería que T fuera ComparableEnIgualdad, peroel tipo valor de ForwardIt no siempre es T.
|
Se requiere que el tipo valor de ForwardIten su lugar sea AsignablePorCopia. |
Véase también
| Copia un rango de elementos omitiendo los que satisfacen un criterio específico (plantilla de función) | |
| Elimina elementos duplicados consecutivos en un rango. (plantilla de función) | |
(C++20)(C++20) |
Elimina elementos que satisfacen un criterio específico. (niebloid) |