Imagine you have a vector of integers and you want to remove all zeros. It sounds like a simple task, right? Well, before C++20, it wasn't that obvious. Let's see how C++20 makes things easier.
Before
Since the beginning of C++, there is a free function named std::remove()
. Young padawans may naively use it like this:
#include <iostream>
#include <vector>
int main() {
std::vector data{12, 0, 654, 0, 4587, 0, 42};
for (const auto& e: data) {
std::cout << e << '\t';
}
std::cout << '\n';
std::remove(data.begin(), data.end(), 0);
for (const auto& e: data) {
std::cout << e << '\t';
}
}
They would get this weird result:
12 0 654 0 4587 0 42
12 654 4587 42 4587 0 42
If we get a closer look at the description of the function on cppreference, we see:
A call to remove is typically followed by a call to a container's
erase
method, which erases the unspecified values and reduces the physical size of the container to match its new logical size.
Hence, the correct way to erase elements prior to C++20 is:
int main() {
std::vector data{12, 0, 654, 0, 4587, 0, 42};
for (const auto& e: data) {
std::cout << e << '\t';
}
std::cout << '\n';
const auto logicalEnd = std::remove(data.begin(), data.end(), 0);
data.erase(logicalEnd, data.end());
for (const auto& e: data) {
std::cout << e << '\t';
}
}
The result is correct this time:
12 0 654 0 4587 0 42
12 654 4587 42
This technique is know as the Erase–remove idiom.
Now
C++20 includes proposals P1209r0 and P1115r3. We now have free functions called std::erase()
that are overloaded for the containers of the STL. They perform the remove-erase idiom.
To erase elements in a vector, you can now simply do:
#include <iostream>
#include <vector>
int main() {
std::vector data{12, 0, 654, 0, 4587, 0, 42};
for (const auto& e: data) {
std::cout << e << '\t';
}
std::cout << '\n';
const auto count = std::erase(data, 0);
std::cout << count << " elements erased\n";
for (const auto& e: data) {
std::cout << e << '\t';
}
}
Much simpler, right?
Top comments (2)
Nice, we have this finally!
Finally!