std::remove, std::remove_if
Определено в заголовочном файле <algorithm> | ||
|---|---|---|
template< class ForwardIt, class T > ForwardIt remove( ForwardIt first, ForwardIt last, const T& value ); | (1) |
(до C++26) (constexpr начиная с C++20) |
template< class ForwardIt, class T = typename std::iterator_traits
<ForwardIt>::value_type >
constexpr ForwardIt remove( ForwardIt first, ForwardIt last,
const T& value );
| (начиная с C++26) | |
template< class ExecutionPolicy, class ForwardIt, class T >
ForwardIt remove( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, const T& value );
| (2) |
(начиная с C++17) (до 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 );
| (начиная с 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,
ForwardIt first, ForwardIt last, UnaryPred p );
| (4) | (начиная с C++17) |
Удаляет из диапазона [first, last) все элементы, удовлетворяющие заданным критериям, и возвращает итератор за новым концом диапазона.
value (с использованием operator==).p возвращает true.policy.true: |
| (до C++20) |
|
| (начиная с C++20) |
| Если тип значения | (до C++11) |
| Если тип | (начиная с C++11) |
Пояснение
Удаление выполняется путём сдвига элементов диапазона таким образом, чтобы элементы, которые не нужно удалять, оказались в начале диапазона.
- Сдвиг выполняется с помощью оператора копирующего присваивания(до C++11)оператора перемещающего присваивания(начиная с C++11).
- Операция удаления является стабильной: относительный порядок элементов, которые не нужно удалять, сохраняется.
- Базовая последовательность
[first,last)не укорачивается в результате операции удаления. Пустьresult— возвращённый итератор: - Все итераторы в
[result,last)по-прежнему допускают разыменование.
| (начиная с C++11) |
Параметры
| first, last | - | пара итераторов, задающих диапазон обрабатываемых элементов |
| value | - | значение элементов, которые нужно удалить |
| policy | - | используемая политика выполнения |
| p | - | унарный предикат, который возвращает true, если элемент нужно удалить. Выражение |
| Требования к типам | ||
-ForwardIt должен удовлетворять требованиям LegacyForwardIterator. |
||
-UnaryPredicate должен удовлетворять требованиям Predicate. |
||
Возвращаемое значение
Итератор за концом нового диапазона значений (если это не end, то он указывает на неуточнённое значение; то же относится к итераторам, указывающим на значения между этим итератором и end).
Сложность
Пусть \(\scriptsize N\)N — это std::distance(first, last):
p.Исключения
Перегрузки с параметром шаблона с именем 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;
}
|
Примечания
За вызовом remove обычно следует вызов функции-члена контейнера erase, которая фактически удаляет элементы из контейнера. Эти два вызова вместе образуют так называемый идиом erase-remove.
| Того же эффекта можно добиться с помощью следующих нешаблонных функций:
| (начиная с C++20) |
Одноимённые функции-члены контейнеров list::remove, list::remove_if, forward_list::remove и forward_list::remove_if стирают удалённые элементы.
Эти алгоритмы нельзя использовать с ассоциативными контейнерами, такими как std::set и std::map, поскольку их типы итераторов не разыменовываются в типы, удовлетворяющие требованиям MoveAssignable (ключи в этих контейнерах нельзя изменять).
Стандартная библиотека также определяет перегрузку std::remove в <cstdio>, которая принимает constchar* и используется для удаления файлов.
Поскольку std::remove принимает value по ссылке, его поведение может быть неожиданным, если это ссылка на элемент диапазона [first, last).
| Макрос проверки возможностей | Значение | Стандарт | Возможность |
|---|---|---|---|
__cpp_lib_algorithm_default_value_type | 202403 | (C++26) | Инициализация списком для алгоритмов (1,2) |
Пример
Следующий код удаляет все пробелы из строки, сдвигая все непробельные символы влево, а затем стирая лишние элементы. Это пример идиомы erase-remove.
#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 | Применён к | Опубликованное поведение | Корректное поведение |
|---|---|---|---|
| LWG 283 | C++98 |
T должен был удовлетворять требованиям EqualityComparable, однакотип значения ForwardIt не всегда удовлетворяет этому требованию T | вместо этого тип значения ForwardIt должен былудовлетворять требованиям CopyAssignable |
См. также
| копирует диапазон элементов, исключая те, которые удовлетворяют заданным критериям (шаблон функции и функциональный объект алгоритма) |
|
|
(C++20)(C++20) | |
| удаляет из диапазона подряд идущие повторяющиеся элементы (шаблон функции и функциональный объект алгоритма) |
|
|
(C++20) | |
|
(C++20)(C++20) | удаляет элементы, удовлетворяющие заданным критериям (функциональный объект алгоритма) |
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/algorithm/remove