Updating is assigning
To change what a key maps to in an unordered_map, you assign a new value through the bracket operator. Nothing special marks it as an "update". The same syntax adds a new key when the key is missing and replaces the value when it exists:
unordered_map<string, int> scores;
scores["Alice"] = 95;
scores["Bob"] = 87;
scores["Alice"] = 99; // update: Alice is now 99
scores["Charlie"] = 72; // add new entry
After these lines the map holds three entries: Alice with 99, Bob with 87 and Charlie with 72. The old value 95 is gone. A key appears only once, so there is no way to end up with two Alices.
Why it works
The expression scores["Alice"] returns a reference to the value stored for that key. If the key is missing, the map first creates an entry holding a default value (0 for an int), and then returns a reference to it. Either way, the reference points at real storage inside the map, so assigning to it changes the map.
Because it is a reference, the other assignment operators work too:
scores["Bob"] += 5; // 87 becomes 92
scores["Bob"]++; // 92 becomes 93
This is the usual way to count things. counts[word]++ starts a new word at 0 and raises it to 1, and raises it by 1 each time the word comes up again. The fact that missing keys start from zero is what makes this work without a check.
insert_or_assign
C++17 added the member function insert_or_assign, which does the same job with a clearer name:
scores.insert_or_assign("Alice", 99);
If "Alice" exists, her value is replaced by 99. Otherwise a new entry is created. The function returns a pair, whose second part is true when a new entry was inserted and false when an existing one was assigned, which tells you what happened. Its advantage over [] is that it does not require the value type to be default constructible. For an int map both are fine, and most code just uses [].
insert does not update
The older member insert behaves differently: it adds a pair only when the key is absent, and leaves an existing entry untouched.
scores.insert({"Alice", 1}); // does nothing, Alice stays 99
This is useful when you want a "set only if missing" rule, but it is a trap when you expected an update. If your update seems to be ignored, check that you did not call insert.
Updating an entry that might not exist
Since [] creates missing keys, a typo in the key silently adds a new entry. To update only when the key is there, test first:
if (scores.count("Alice") > 0) {
scores["Alice"] = 99;
}
Or find the entry and write through the iterator: it->second = 99 after auto it = scores.find("Alice"); and a check that it != scores.end().
The exercise, step by step
The editor starts with a map holding Alice at 95 and Bob at 87. The task is to set Alice's score to 99.
- Pick the key. Alice is already in the map, so this changes the existing entry.
- Assign the new value. Write
scores["Alice"] = 99;on a line below the existing code.
unordered_map<string, int> scores;
scores["Alice"] = 95;
scores["Bob"] = 87;
scores["Alice"] = 99;
The map still has two entries. Alice's value is now 99 and Bob's is still 87. Do not declare a new variable. The statement changes the map that already exists.
Common mistakes
- Writing
int scores["Alice"] = 99;or declaring a new variable. Updating is a plain assignment to an existing map. - Using
insertto update. It leaves an existing key alone. - Misspelling the key. The map adds a new entry instead of reporting an error, and the real key keeps its old value. Keys are case sensitive.
- Using
==for assignment.scores["Alice"] == 99compares and changes nothing.
Key takeaways
m[key] = valuereplaces the value if the key exists and adds the pair if it does not.+=and++work on map values, and make counting easy.insert_or_assignis the explicit C++17 version, whileinsertnever overwrites.