C/C++ Arena

Step 6 of 6

Erase with a condition

Removing every element that matches a condition sounds simple, but erasing inside a loop is a known trap: after v.erase(it), the iterator it is invalid, and indexes shift under you. The standard library solves it properly.

C++20 gives you a single call:

#include <iostream>
#include <string>
#include <vector>

struct Task {
    std::string title;
    bool done;
};

int main() {
    std::vector<int> v = {5, -2, 8, -1, 0, 3};
    auto removed = std::erase_if(v, [](int x) { return x < 0; });
    for (int x : v) std::cout << x << " ";
    std::cout << "(removed " << removed << ")\n";

    std::vector<Task> tasks = {{"shop", true}, {"code", false}, {"sleep", true}};
    std::erase_if(tasks, [](const Task& t) { return t.done; });
    for (const auto& t : tasks) std::cout << t.title << "\n";

    std::string s = "b-a-n-a-n-a";
    std::erase(s, '-');                      // remove a specific value
    std::cout << s << "\n";
}
5 8 0 3 (removed 2)
code
banana

How it works

The old way: erase-remove

Before C++20 you'd see this idiom everywhere, and you'll still meet it in existing code:

v.erase(std::remove_if(v.begin(), v.end(), pred), v.end());

std::remove_if doesn't actually shrink the vector (an algorithm only sees iterators, not the container). It moves the elements to keep to the front and returns an iterator to the new logical end. v.erase(that, v.end()) then chops off the leftovers. Forgetting the erase part is a classic bug: the size never changes.

Predicates on pairs

Your vector holds std::pair<std::string, int>, so the lambda takes const std::pair<std::string, int>& p (or const auto& p) and looks at p.second. Read the condition carefully: "0 or less" means <= 0.

Your turn: write void drop_dead(std::vector<std::pair<std::string, int>>& players) that removes players whose hp (the int) is 0 or less.

Previous: Captures