Debugging challengeIntermediate
Erasing while iterating
Scenario
A cache-eviction routine removes every expired entry from an unordered_map and every non-positive value from a vector. Under AddressSanitizer both loops report heap-use-after-free; without it the program sometimes skips elements and sometimes segfaults. Find the bug in each loop.
1#include <iostream>2#include <unordered_map>3#include <vector>4#include <string>5using namespace std;6 7void evictExpired(unordered_map<string, int>& ttl, int now) {8 for (auto it = ttl.begin(); it != ttl.end(); ++it) {9 if (it->second <= now)10 ttl.erase(it); // invalidates it, then ++it11 }12}13 14void removeNonPositive(vector<int>& v) {15 for (size_t i = 0; i < v.size(); ++i) {16 if (v[i] <= 0)17 v.erase(v.begin() + i); // shifts the next element into slot i18 }19}20 21int main() {22 unordered_map<string, int> ttl = {{"a", 1}, {"b", 5}, {"c", 2}};23 evictExpired(ttl, 3);24 vector<int> v = {3, 0, 0, -1, 4};25 removeNonPositive(v);26 for (int x : v) cout << x << ' '; // expected: 3 427}Your task
- For the
unordered_maploop, explain what the standard says about an iterator aftererase(it), and why++itafterwards is undefined behaviour. - For the
vectorloop, tracev = {3, 0, 0, -1, 4}by hand and show which element is skipped. - Fix both loops. For the vector, give two fixes: one that keeps the index loop and one that is
O(n). - Which containers guarantee that erasing one element does not invalidate iterators to the others?
- State the complexity of each fixed loop.
DebuggingImplementationSystematic Reasoning
Work it out
Write your analysis before revealing anything. The self-check below compares it against what a strong answer contains.
Reveal
Progressive — each section builds on the previous one.
The bug
Why it happens
The fix
Edge cases
Complexity
Self-check
Tick what your analysis covered. Be honest — this feeds your readiness profile.