std:: remove, std:: remove_if
|
Определено в заголовке
<algorithm>
|
||
| (1) | ||
|
template
<
class
ForwardIt,
class
T
>
ForwardIt remove ( ForwardIt first, ForwardIt last, const T & value ) ; |
(constexpr начиная с C++20)
(до C++26) |
|
|
template
<
class
ForwardIt,
class
T
=
typename
std::
iterator_traits
<
ForwardIt
>
::
value_type
>
|
(начиная с C++26) | |
| (2) | ||
|
template
<
class
ExecutionPolicy,
class
ForwardIt,
class
T
>
ForwardIt remove
(
ExecutionPolicy
&&
policy,
|
(начиная с C++17)
(до C++26) |
|
|
template
<
class
ExecutionPolicy,
class
ForwardIt,
class
T
=
typename
std::
iterator_traits
|
(начиная с C++26) | |
|
template
<
class
ForwardIt,
class
UnaryPred
>
ForwardIt remove_if ( ForwardIt first, ForwardIt last, UnaryPred p ) ; |
(3) | (constexpr начиная с C++20) |
|
template
<
class
ExecutionPolicy,
class
ForwardIt,
class
UnaryPred
>
ForwardIt remove_if
(
ExecutionPolicy
&&
policy,
|
(4) | (начиная с C++17) |
Удаляет все элементы, удовлетворяющие определённым критериям, из диапазона
[
first
,
last
)
и возвращает итератор, указывающий за новый конец диапазона.
|
std:: is_execution_policy_v < std:: decay_t < ExecutionPolicy >> является true . |
(до C++20) |
|
std:: is_execution_policy_v < std:: remove_cvref_t < ExecutionPolicy >> является true . |
(начиная с C++20) |
|
Если
тип значения
|
(до C++11) |
|
Если тип * first не является MoveAssignable , поведение не определено. |
(начиная с C++11) |
Содержание |
Объяснение
Удаление осуществляется путем сдвига элементов в диапазоне таким образом, что элементы, которые не должны быть удалены, появляются в начале диапазона.
- Сдвиг выполняется с помощью copy assignment (until C++11) move assignment (since C++11) .
- Операция удаления стабильна: относительный порядок элементов, которые не должны быть удалены, остается неизменным.
-
Базовая последовательность
[first,last)не укорачивается операцией удаления. Принимая result за возвращенный итератор:
-
-
Все итераторы в
[result,last)остаются разыменуемыми .
-
Все итераторы в
|
(начиная с C++11) |
Параметры
| first, last | - | пара итераторов, определяющих диапазон обрабатываемых элементов |
| value | - | значение элементов для удаления |
| policy | - | используемая политика выполнения |
| p | - |
унарный предикат, который возвращает
true
если элемент должен быть удален.
Выражение
p
(
v
)
должно быть преобразуемо в
bool
для каждого аргумента
|
| Требования к типам | ||
-
ForwardIt
должен удовлетворять требованиям
LegacyForwardIterator
.
|
||
-
UnaryPredicate
должен удовлетворять требованиям
Predicate
.
|
||
Возвращаемое значение
Итератор за концом нового диапазона значений (если это не end , то он указывает на неопределённое значение, как и итераторы любых значений между этим итератором и end ).
Сложность
Дано N как std:: distance ( first, last ) :
Исключения
Перегрузки с параметром шаблона с именем
ExecutionPolicy
сообщают об ошибках следующим образом:
-
Если выполнение функции, вызванной как часть алгоритма, выбрасывает исключение и
ExecutionPolicyявляется одним из стандартных политик , std::terminate вызывается. Для любого другогоExecutionPolicyповедение определяется реализацией. - Если алгоритму не удается выделить память, std::bad_alloc выбрасывается.
Возможная реализация
| 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; } |
` тегов сохранены без изменений. Только текстовые элементы вне тегов кода были переведены на русский язык с сохранением профессиональной терминологии C++.
Примечания
Вызов
remove
обычно сопровождается вызовом функции-члена
erase
контейнера для фактического удаления элементов из контейнера. Эти два вызова вместе образуют так называемый
erase-remove idiom
.
|
Того же эффекта можно достичь с помощью следующих нечленных функций:
|
(since C++20) |
Аналогично названные функции-члены контейнеров member functions 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
)
.
| Макрос тестирования возможностей | Значение | Стандарт | Возможность |
|---|---|---|---|
__cpp_lib_algorithm_default_value_type
|
202403
|
(C++26) | List-инициализация для алгоритмов ( 1,2 ) |
Пример
Следующий код удаляет все пробелы из строки, сдвигая все непробельные символы влево и затем стирая лишнее. Это пример 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}})); }
Вывод:
1) "Quick Red Dog" 2) "QuickRedDog Dog" 3) "QuickRedDog", size: 15 4) "QuickRedDog", size: 11 5) "JumpedOverALazyFox"
Отчёты о дефектах
Следующие отчеты об изменениях в поведении, содержащие описания дефектов, были применены ретроактивно к ранее опубликованным стандартам C++.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| LWG 283 | C++98 |
T
was required to be
EqualityComparable
, but
the value type of
ForwardIt
is not always
T
|
required the value type of
ForwardIt
to be CopyAssignable instead |
Смотрите также
|
копирует диапазон элементов, пропуская те, которые удовлетворяют определённым критериям
(шаблон функции) |
|
|
удаляет последовательные дублирующиеся элементы в диапазоне
(шаблон функции) |
|
|
(C++20)
(C++20)
|
удаляет элементы, удовлетворяющие определённым критериям
(функциональный объект алгоритма) |