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 turn: 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.

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