Erase–remove idiom
The erase–remove idiom is a common C++ technique to eliminate elements that fulfill a certain criterion from a C++ Standard Library container.[1][2][3]
Motivation
A common programming task is to remove all elements that have a certain value or fulfill a certain criterion from a collection. In C++, this can be achieved using a hand-written loop. It is, however, preferable to use an algorithm from the C++ Standard Library for such tasks.[1][2][3]
The member function erase
can be used to delete an element from a collection, but for containers which are based on an array, such as vector
, all elements after the deleted element have to be moved forward to avoid "gaps" in the collection. Calling erase multiple times on the same container generates much overhead from moving the elements.
The algorithm
library provides the remove
and remove_if
algorithms for this. Because these algorithms operate on a range of elements denoted by two forward iterators, they have no knowledge of the underlying container or collection.[1][4]
These algorithms do not remove elements from the container, but move all elements that do not fit the removal criteria to the front of the range, keeping the relative order of the elements. This is done in a single pass through the data range.
As no elements are actually removed and the container retains the same size, the tail of the array has a length equal to the number of "removed" items; these items remain in memory but in an unspecified state. remove
returns an iterator pointing to the first of these tail elements so that they can be deleted using a single call to erase
.
Doing the same using only erase
results in as many passes as there are elements to remove. For each of these passes, all elements after the erased element have to be moved, which is more time-consuming than shifting elements in a single pass.
C++20
As of C++20, the free functions std::erase
and std::erase_if
are provided for STL containers. These convenience functions can be used to perform correct erasure of elements without requiring the programmer to explicitly use the erase-remove idiom.[5]
Limitation
The erase–remove idiom cannot be used for containers that return const_iterator
(e.g.: set)[6]
std::remove
and/or std::remove_if
do not maintain elements that are removed (unlike std::partition
, std::stable_partition
). Thus, erase–remove can only be used with containers holding elements with full value semantics without incurring resource leaks.[7]
Example
// Use g++ -std=c++11 or clang++ -std=c++11 to compile.
#include <algorithm> // remove and remove_if
#include <iostream>
#include <vector>
void Print(const std::vector<int>& vec) {
for (auto val : vec) {
std::cout << val << ' ';
}
std::cout << '\n';
}
int main() {
std::vector<int> v = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
Print(v);
// Removes all elements with the value 5.
v.erase(std::remove(v.begin(), v.end(), 5), v.end());
Print(v);
// Removes all odd numbers.
v.erase(std::remove_if(v.begin(), v.end(), [](int val) { return val & 1; }),
v.end());
Print(v);
}
/*
Output:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 6 7 8 9
0 2 4 6 8
*/
References
- Meyers, Scott (2001). Effective STL: 50 Specific Ways to Improve Your Use of the Standard Template Library. Addison-Wesley.
- Sutter, Herb; Alexandrescu, Andrei (2004). C++ Coding Standards: 101 Rules, Guidelines, and Best Practices. Addison-Wesley.
- Scott Meyers, "STL Algorithms vs. Hand-Written Loops", Dr. Dobbs, October 25, 2001.
- Josuttis, Nicolai (1999). C++ Standard Library – A Tutorial and Reference. Addison-Wesley.
- "std::erase, std::erase_if (std::vector) - cppreference.com". en.cppreference.com. Retrieved 9 December 2021.
- "Erase–remove idiom with std::set". stackoverflow.com. Stack Overflow. 25 September 2010. Retrieved 14 April 2013.
- Meyers, Scott (2001). Effective STL : 50 specific ways to improve your use of the standard template library. Boston: Addison-Wesley. pp. 143–145. ISBN 0201749629. OCLC 46713127.