std::remove, std::remove_if
| Defined in header <algorithm>
|
||
template< class ForwardIt, class T >
ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );
|
(1) | (constexpr since C++20) (until C++26) |
template< class ForwardIt, class T = typename std::iterator_traits
<ForwardIt>::value_type >
constexpr ForwardIt remove( ForwardIt first, ForwardIt last,
const T& value );
|
(since C++26) | |
template< class ForwardIt, class UnaryPred >
ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPred p );
|
(2) | (constexpr since C++20) |
template< class ExecutionPolicy, class ForwardIt, class T >
ForwardIt remove( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, const T& value );
|
(3) | (since C++17) (until 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 );
|
(since C++26) | |
template< class ExecutionPolicy, class ForwardIt, class UnaryPred >
ForwardIt remove_if( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, UnaryPred p );
|
(4) | (since C++17) |
“Removes” all elements satisfying specific criteria from the target range [first, last).
remove removes all elements that are equal to value (using operator==).remove_if removes all elements for which predicate p returns true.policy.true:
|
|
(until C++20) |
|
|
(since C++20) |
Removing is done by partitioning the elements in the target range. Given the partition point result, all elements that are not to be removed appear in [first, result), while other elements can only appear in [result, last).
- The underlying sequence of the target range is not shortened by the removing operation.
- Elements are shifted by copy assignment(until C++11)move assignment(since C++11).
- All iterators in
[result,last)are still dereferenceable, and each element of[result,last)has a valid but unspecified state(since C++11). - The removing operation is stable: the relative order of the elements not to be removed stays the same.
|
If the value type of |
(until C++11) |
|
If the type of |
(since C++11) |
Parameters
| first, last | - | the pair of iterators defining the target range |
| value | - | the value of elements to remove |
| p | - | unary predicate which returns true if the element should be removed. The expression |
| policy | - | the execution policy to use |
| Type requirements | ||
-ForwardIt must meet the requirements of LegacyForwardIterator.
| ||
-UnaryPredicate must meet the requirements of Predicate.
| ||
Return value
The iterator result mentioned above.
Complexity
Given N as std::distance(first, last):
operator==.p.Exceptions
- If the temporary memory resources required for parallelization are not available, std::bad_alloc is thrown.
- If an uncaught exception is thrown while accessing objects via an algorithm argument, the behavior is determined by the execution policy (for standard policies, std::terminate is invoked).
Possible implementation
| remove |
|---|
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 |
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;
}
|
Notes
A call to remove is typically followed by a call to a container's erase member function to actually remove elements from the container. These two invocations together constitute a so-called erase-remove idiom.
|
The same effect can also be achieved by the following non-member functions:
|
(since C++20) |
The similarly-named container member functions list::remove, list::remove_if, forward_list::remove, and forward_list::remove_if erase the removed elements.
These algorithms cannot be used with associative containers such as std::set and std::map because their iterator types do not dereference to MoveAssignable types (the keys in these containers are not modifiable).
The standard library also defines an overload of std::remove in <cstdio>, which takes a const char* and is used to delete files.
Because std::remove takes value by reference, it can have unexpected behavior if it is a reference to an element of the target range.
| Feature-test macro | Value | Std | Feature |
|---|---|---|---|
__cpp_lib_algorithm_default_value_type |
202403 |
(C++26) | List-initialization for algorithms (1,3) |
Example
The following code removes all spaces from a string by shifting all non-space characters to the left and then erasing the extra. This is an example of 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}}));
}
Output:
1) "Quick Red Dog"
2) "QuickRedDog Dog"
3) "QuickRedDog", size: 15
4) "QuickRedDog", size: 11
5) "JumpedOverALazyFox"
Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
| DR | Applied to | Behavior as published | Correct behavior |
|---|---|---|---|
| LWG 283 | C++98 | T was required to be EqualityComparable, butthe value type of ForwardIt is not always T
|
required the value type of ForwardItto be CopyAssignable instead |
See also
(C++20)(C++20) |
removes elements satisfying specific criteria (algorithm function object) |
| copies a range of elements omitting those that satisfy specific criteria (function template & algorithm function object) | |
(C++20)(C++20) |
|
| removes consecutive duplicate elements in a range (function template & algorithm function object) | |
(C++20) |