DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Pierre Gradot
Pierre Gradot

Posted on

Let's try C++20 | Erase elements in a container with std::erase()

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';
    }
}
Enter fullscreen mode Exit fullscreen mode

They would get this weird result:

12      0       654     0       4587    0       42
12      654     4587    42      4587    0       42
Enter fullscreen mode Exit fullscreen mode

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';
    }
}

Enter fullscreen mode Exit fullscreen mode

The result is correct this time:

12      0       654     0       4587    0       42
12      654     4587    42
Enter fullscreen mode Exit fullscreen mode

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';
    }
}
Enter fullscreen mode Exit fullscreen mode

Much simpler, right?

Top comments (2)

Collapse
sandordargo profile image
Sandor Dargo

Nice, we have this finally!

Collapse
pgradot profile image
Pierre Gradot Author

Finally!

🌚 Life is too short to browse without dark mode