C/C++ Arena

Step 4 of 6

Review: modifying while iterating

Another classic: changing a container while looping over it.

Spotting the skip

Run the erase loop by hand on an input with two matches next to each other, like {a, X, X, b} where X should be removed:

i = 1: erase X  -> {a, X, b}   then i++ -> i = 2
i = 2: b                       the second X, now at index 1, was never checked

The safe patterns: only increment when nothing was erased, use std::erase_if, or build a new vector of the items you keep.

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

int main() {
    std::vector<std::string> queue = {"ok", "spam", "spam", "ok", "spam"};
    for (std::size_t i = 0; i < queue.size(); ) {
        if (queue[i] == "spam") queue.erase(queue.begin() + i);   // don't advance
        else i++;                                                  // advance only when keeping
    }
    for (const auto& m : queue) std::cout << m << " ";
    std::cout << "(" << queue.size() << ")\n";

    std::vector<int> v = {1, 2, 3};
    int first = v.front();                // a copy, not a reference: safe after growth
    for (int i = 0; i < 100; i++) v.push_back(i);
    std::cout << first << "\n";
}
ok ok (2)
1

Adding while looping

A range-for over roster that calls roster.push_back is undefined behavior: the loop's hidden iterators point into the old buffer after a reallocation. If you need to add a number of items, compute the count first, then add them in a separate plain loop that doesn't iterate over the container.

The dangling reference

const std::string& captain = roster.front(); refers to an element inside the vector. After push_back reallocates, it refers to freed memory. Copy the value (std::string captain = ...) when you need it to survive changes to the container.

Your task

This pull request enforces bans and fills the roster back up with substitutes. Fix it so that every banned player is removed (including when two are adjacent), one substitute is added per removed player, and captain returns the right name. There are three bugs.

Challenge 2

This pull request removes expired sessions from a map while looping over it with a range-for, which invalidates the loop's iterator as soon as an entry is erased. It also returns the wrong count. Fix expire so it removes every session with expires <= now and returns how many it removed.

Challenge 3

This pull request squeezes runs of spaces in chat messages: every run of spaces becomes a single space, and spaces at the start and end are removed. Erasing inside the index loop skips characters, so runs of three spaces survive, and the trimming misses a case. Fix squeeze.

Previous: Review: leaks on the error path Next: Review: integer math