std::remove,std::remove_if(3)
π std::remove,std::remove_if(3) π
okay so this is the std::remove,std::remove_if(3) page from the C++ Standard Libary manual, and itβs lowkey one of the most useful algorithm pages youβll ever meet. Itβs giving βI shift your elements around and hand you a new end iteratorβ energy. Letβs get into it, bestie π«Ά.
πΈ NAME πΈ
std::remove, std::remove_if β yes, the name is literally std::remove,std::remove_if, and thatβs the whole vibe. Cute, concise, iconic.
β¨ Synopsis β¨
Defined in header <algorithm>
(1)
template< class ForwardIt, class T >
ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );
(constexpr since C++20)
(until C++26)
(1)
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)
(2)
template< class ExecutionPolicy, class ForwardIt, class T >
ForwardIt remove( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, const T& value );
(since C++17)
(until C++26)
(2)
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)
(3)
template< class ForwardIt, class UnaryPred >
ForwardIt remove_if( ForwardIt first, ForwardIt last, UnaryPred p );
(constexpr since C++20)
(4)
template< class ExecutionPolicy, class ForwardIt, class UnaryPred >
ForwardIt remove_if( ExecutionPolicy&& policy,
ForwardIt first, ForwardIt last, UnaryPred p );
(since C++17)
Removes all elements satisfying specific criteria from the range [first, last) and returns a past-the-end iterator for the new end of the range.
1)β removes all elements that are equal tovalue(usingoperator==).3)β removes all elements for which predicatepreturnstrue.2,4)β same as(1,3), but executed according topolicy. These overloads participate in overload resolution only ifstd::is_execution_policy_v<std::decay_t<ExecutionPolicy>>istrue(until C++20). Since C++20, only ifstd::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>istrue.
If the value type ofForwardItis notCopyAssignable, the behavior is undefined (until C++11). If the type of*firstis notMoveAssignable, the behavior is undefined (since C++11).
π¦ Explanation π¦
Removing is done by shifting the elements in the range in such a way that the elements that are not to be removed appear in the beginning of the range. No cap, thatβs the whole trick.
- Shifting is done by copy assignment (until C++11), or move assignment (since C++11).
- The removing operation is stable: the relative order of the elements not to be removed stays the same. Periodt.
- The underlying sequence of
[first, last)is not shortened by the removing operation. Givenresultas the returned iterator:- All iterators in
[result, last)are still dereferenceable. - Each element of
[result, last)has a valid but unspecified state, because move assignment can eliminate elements by moving from elements that were originally in that range (since C++11).
- All iterators in
π Parameters π
first,lastβ the range of elements to process.valueβ the value of elements to remove.policyβ the execution policy to use. See execution policy for details.pβ unary predicate which returnstrueif the element should be removed. The expressionp(v)must be convertible toboolfor every argumentvof type (possibly const)VT, whereVTis the value type ofForwardIt, regardless of value category, and must not modifyv. Thus, a parameter type ofVT&is not allowed, nor isVTunless forVTa move is equivalent to a copy (since C++11).
π Type requirements π
ForwardItmust meet the requirements ofLegacyForwardIterator.UnaryPredicatemust meet the requirements ofPredicate.
π« Return value π«
Past-the-end iterator for the new range of values (if this is not end, then it points to an unspecified value, and so do iterators to any values between this iterator and end).
π₯ Complexity π₯
Given (\scriptsize N)N as std::distance(first, last):
1,2)β exactly (\scriptsize N)N comparisons usingoperator==.3,4)β exactly (\scriptsize N)N applications of the predicatep.
π Exceptions π
The overloads with a template parameter named ExecutionPolicy report errors as follows:
- If execution of a function invoked as part of the algorithm throws an exception and
ExecutionPolicyis one of the standard policies,std::terminateis called. For any otherExecutionPolicy, the behavior is implementation-defined. - If the algorithm fails to allocate memory,
std::bad_allocis thrown.
π§ Possible implementation π§
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;
}
π Notes π
- A call to
removeis typically followed by a call to a containerβserasemember 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):
std::erase, which has overloads for all standard sequence containers.std::erase_if, which has overloads for all standard containers.
- The similarly-named container member functions
list::remove,list::remove_if,forward_list::remove, andforward_list::remove_iferase the removed elements. - These algorithms cannot be used with associative containers such as
std::setandstd::mapbecause their iterator types do not dereference toMoveAssignabletypes (the keys in these containers are not modifiable). - The standard library also defines an overload of
std::removein<cstdio>, which takes aconst char*and is used to delete files. - Because
std::removetakesvalueby reference, it can have unexpected behavior if it is a reference to an element of the range[first, last).
Warning bestie: that last one is a real βbe carefulβ moment. If value is a reference into the same range, the vibes are not immaculate.
Feature-test macro
__cpp_lib_algorithm_default_value_typeβ value202403, standard(C++26), feature: βList-initialization for algorithms (1,2)β.
π 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.
// Run this code
#include <algorithm>
#include <cassert>
#include <cctype>
#include <complex>
#include <iostream>
#include <string>
#include <string_view>
#include <vector>
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';
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 β
Textwithsomespaces size: 23
Textwithsomespaces size: 18
Textwithsomewhitespaces
π Defect reports π
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
- DR:
LWG 283β applied to:C++98. Behavior as published: βTwas required to beEqualityComparable, but the value type ofForwardItis not alwaysTβ. Correct behavior: βrequired the value type ofForwardItto beCopyAssignableinsteadβ.
π See also π
remove_copy,remove_copy_ifβ copies a range of elements omitting those that satisfy specific criteria (function template).uniqueβ removes consecutive duplicate elements in a range (function template).ranges::remove(C++20),ranges::remove_if(C++20) β removes elements satisfying specific criteria (niebloid).
okay thatβs the whole page, bestie π β source/version: http://cppreference.com, date: 2024.06.10, and the page is std::remove,std::remove_if(3). now go forth and erase responsibly β¨
π¦ where this page comes from
- nixpkgs unstable: stdman 2024.07.05
- opensuse-leap 16.0: stdman 2024.07.05-bp160.1.9 Β· MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms