std::remove, std::remove_if
Определено в заголовке <algorithm> | ||
|---|---|---|
| (1) | ||
template< class ForwardIt, class T > ForwardIt remove( ForwardIt first, ForwardIt last, const T& value ); | (до C++20) | |
template< class ForwardIt, class T > constexpr ForwardIt remove( ForwardIt first, ForwardIt last, const T& value ); | (с C++20) | |
template< class ExecutionPolicy, class ForwardIt, class T >
ForwardIt remove( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, const T& value );
| (2) | (с C++17) |
| (3) | ||
template< class ForwardIt, class UnaryPredicate > ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPredicate p ); | (до C++20) | |
template< class ForwardIt, class UnaryPredicate >
constexpr ForwardIt remove_if( ForwardIt first, ForwardIt last,
UnaryPredicate p );
| (с C++20) | |
template< class ExecutionPolicy, class ForwardIt, class UnaryPredicate >
ForwardIt remove_if( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, UnaryPredicate p );
| (4) | (с C++17) |
Удаляет все элементы, удовлетворяющие определённым критериям, из диапазона [first, last) и возвращает итератор, указывающий на конец нового диапазона.
value (используя operator==). p возвращает true. policy. Эти перегрузки не участвуют в разрешении перегрузки, если |
| (до C++20) |
|
| (с C++20) |
| Если тип значения | (до C++11) |
| Если тип | (с C++11) |
Удаление выполняется путём сдвига (при помощи копирующей операции присваивания(до C++11)перемещения присваивания(с C++11)) элементов в диапазоне таким образом, что элементы, которые не должны быть удалены, появляются в начале диапазона. Относительный порядок оставшихся элементов сохраняется, а физический размер контейнера не изменяется. Итераторы, указывающие на элемент между новым логическим концом и физическим концом диапазона, по-прежнему доступны, но сами элементы имеют неопределённые значения (в соответствии с MoveAssignable пост-условием)(с C++11).
Параметры
| first, last | - | диапазон обрабатываемых элементов |
| value | - | значение удаляемых элементов |
| policy | - | используемая политика выполнения. Подробности см. в политике выполнения. |
| p | - | унарный предикат, возвращающий true, если элемент должен быть удалён.Выражение |
| Требования к типу | ||
-ForwardIt должно соответствовать требованиям LegacyForwardIterator. |
||
-UnaryPredicate должно соответствовать требованиям Predicate. |
||
Возвращаемое значение
Итератор, указывающий на конец нового диапазона значений (если это не end, то он указывает на неопределённое значение, так же как и итераторы на любые значения между этим итератором и end).
Сложность
При условии N как std::distance(first, last):
N сравнений с value с использованием operator==.N применений предиката p.Исключения
Перегрузки с параметром шаблона ExecutionPolicy сообщают об ошибках следующим образом:
- Если при выполнении функции, вызываемой как часть алгоритма, возникает исключение и
ExecutionPolicy— одна из стандартных политик, вызываетсяstd::terminate. Для любой другойExecutionPolicy, поведение неопределено. - Если алгоритм не может выделить память, выбрасывается
std::bad_alloc.
Примечания
Вызов remove обычно следует за вызовом члена контейнера erase для удаления неопределённых значений и уменьшения физического размера контейнера до совпадения с новым логическим размером. Эти два вызова вместе составляют так называемый идиому удаления-удаления, которая может быть реализована свободной функцией std::erase с перегрузками для всех стандартных последовательных контейнеров, или std::erase_if с перегрузками для всех стандартных контейнеров(с C++20).
Похожие по названию контейнерные члены-функции list::remove, list::remove_if, forward_list::remove и forward_list::remove_if удаляют удалённые элементы.
Эти алгоритмы нельзя использовать с ассоциативными контейнерами, такими как std::set и std::map, поскольку их типы итераторов не ссылаются на MoveAssignable типы (ключи в этих контейнерах не изменяемы).
Стандартная библиотека также определяет перегрузку std::remove в <cstdio>, которая принимает const char* и используется для удаления файлов.
Поскольку std::remove принимает value по ссылке, это может привести к непредсказуемому поведению, если это ссылка на элемент диапазона [first, last).
Возможная реализация
| remove |
|---|
template<class ForwardIt, class T>
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 |
template<class ForwardIt, class UnaryPredicate>
ForwardIt remove_if(ForwardIt first, ForwardIt last, UnaryPredicate 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;
} |
Пример
Следующий код удаляет все пробелы из строки, сдвигая все символы, отличные от пробела, влево, а затем удаляя лишние. Это пример идиомы удаления-удаления.
#include <algorithm>
#include <cctype>
#include <iostream>
#include <string>
#include <string_view>
int main()
{
std::string str1{"Text with some spaces"};
auto noSpaceEnd = std::remove(str1.begin(), str1.end(), ' ');
// The spaces are removed from the string only logically.
// Note, we use view, the original string is still not shrunk:
std::cout << 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 << str1 << " size: " << str1.size() << '\n';
std::string str2 = "Text\n with\tsome \t whitespaces\n\n";
str2.erase(std::remove_if(str2.begin(),
str2.end(),
[](unsigned char x) { return std::isspace(x); }),
str2.end());
std::cout << str2 << '\n';
}Вывод:
Textwithsomespaces size: 23 Textwithsomespaces size: 18 Textwithsomewhitespaces
Отчёты об ошибках
Следующие отчёты об ошибках, изменяющие поведение, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Применено к | Поведение, как опубликовано | Правильное поведение |
|---|---|---|---|
| LWG 283 | C++98 |
T должен был быть EqualityComparable, нотип значения ForwardIt не всегда T | требовалось, чтобы тип значения ForwardItбыл CopyAssignable вместо |
См. также
| копирует диапазон элементов, опуская те, которые удовлетворяют определенным критериям (шаблон функции) |
|
| удаляет последовательные дублирующие элементы в диапазоне (шаблон функции) |
|
|
(C++20)(C++20) | удаляет элементы, удовлетворяющие определенным критериям (niebloid) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/w/cpp/algorithm/remove