What the loop does
An unordered_map stores key and value pairs. A range-based for loop visits every entry once, and the body runs once per key. In this lesson the map is scores: each key is a player's name and each value is that player's points.
unordered_map<string, int> stock;
stock["apples"] = 5;
stock["pears"] = 2;
for (auto& [fruit, amount] : stock) {
cout << fruit << " " << amount << endl;
}
This prints the two entries in an order the program doesn't choose. Both of these are possible:
pears 2
apples 5
Reading the loop header
[fruit, amount]is a structured binding. Each entry is a pair, and the binding gives its two parts names:fruitis the key andamountis the value.autolets the compiler work out the types, herestringandint.&makes the names refer to the entry inside the map instead of to a copy.
Older code names the entry and uses its two members: entry.first is the key and entry.second is the value. It is the same pair, only with different names.
What the & changes
With &, assigning to the value changes the map. Without it, the loop works on a copy of each entry, and the map stays as it was. Starting from the scores 12, 7, 15 and 9 (total 43), a loop that adds 1 to every player's points gives these totals:
- with
auto& [name, points], the map's total becomes 47; - with
auto [name, points], the map's total stays 43, because only the copies changed.
When the loop only reads, the & is still the better habit. It avoids copying a string key for every entry.
Two traps
- The order is not fixed. That is what "unordered" means. Code that only adds things up or counts is safe, because the total and the count are the same in any order. Code that needs "the first one" or a sorted listing must not rely on this loop's order.
- Don't add keys inside the loop. Even reading
stock[key]with a key that is missing adds that key with the value 0. Starting with 4 players, readingscores["Zed"]once makes the size 5.scores.count("Zed")asks without adding anything.
The lesson's task
The map holds Ana 12, Ben 7, Cleo 15 and Dan 9. The task is to add every player's points to total and to count, in count, the players with 10 points or more.
- Write the loop with
auto& [name, points]overscores. - Inside it, add
pointstototal. - Still inside, if
pointsis at least 10, add 1 tocount.
unordered_map<string, int> scores;
scores["Ana"] = 12;
scores["Ben"] = 7;
scores["Cleo"] = 15;
scores["Dan"] = 9;
int total = 0;
int count = 0;
for (auto& [name, points] : scores) {
total += points;
if (points >= 10) {
count += 1;
}
}
cout << total << endl;
cout << count << endl;
It prints:
43
2
The total is 12 + 7 + 15 + 9 = 43, and only Ana and Cleo have 10 or more. The variable name is never used in the body. That is fine here, because the binding is there to take the entry apart.
Key takeaways
for (auto& [key, value] : map)visits every entry once.- Use
&to avoid copies, and to change values in place. - The order is unspecified, so totals and counts are safe answers.
- Don't add keys while looping, and remember that
map[key]adds a missing key.
