When a key may be missing
In many programs, a missing key means "none yet". A shop with no plums has 0 plums, and the map simply has no "plums" entry. So you want a value, 0, even when the key is absent.
The square brackets seem to do that. For an unordered_map<string, int>, stock["plums"] gives 0 for a missing key. But it also does something else: it adds the key to the map, with the value 0. So a map with one entry now has two, and stock.size() goes from 1 to 2. A read has changed the map.
The safe pattern: default first, then check
Start with the default in a variable. Then use count to read the real value only when the key is already there.
unordered_map<string, int> stock = {{"apples", 5}};
int plums = 0;
if (stock.count("plums") > 0) {
plums = stock["plums"];
}
cout << plums << endl; // 0
Here the key is missing, so the if body is skipped. plums stays at its default of 0, and stock still has one key. Running the same pattern for "apples" sets the variable to 5.
Other ways to read a missing key
stock.at("plums")does not add anything. On a missing key it throws anout_of_rangeexception, which ends the program unless you catch it.stock.find("plums")returnsstock.end()for a missing key, which you can compare and then read throughit->second.
This lesson uses the count pattern, because it reads the same way as the key check you already know.
The exercise: counting fruit
The map stock counts the fruit in a shop: 5 apples and 2 pears. The starter code already reads and prints the pears. The task is to do the same for plums, which are not in the map:
- Declare
int plums = 0;, the default. - Write an
ifthat checksstock.count("plums") > 0. Inside it, setplumstostock["plums"]. - Print the plums line like the pears line:
We have, the number, thenplums.
unordered_map<string, int> stock = {{"apples", 5}, {"pears", 2}};
int pears = stock["pears"];
cout << "We have " << pears << " pears" << endl;
int plums = 0;
if (stock.count("plums") > 0) {
plums = stock["plums"];
}
cout << "We have " << plums << " plums" << endl;
The output is:
We have 2 pears
We have 0 plums
After this code, stock still holds two entries. If the code had read stock["plums"] directly, the line would print the same 0, but the map would silently have a third entry, plums with 0.
Why the order matters
Declare the default before the if, not inside it. A variable declared inside the braces would disappear at the closing brace, and the final cout line could not use it. With the declaration above the if, one print statement works for both cases, whether the key was there or not.
The same shape, "default, then overwrite if present", works for any type of value. With unordered_map<string, string>, the default could be "unknown".
Key takeaways
- On a missing key,
m[key]inserts the key with a default value (0 for numbers). - To read without changing the map, set the default first and read
m[key]only inside anif (m.count(key) > 0). - The default can be any value that makes sense for your data: 0 for a count, an empty string for text.
