24 Beginner The Hundred
The Read That Writes
asking the question changes the answer
#include <iostream>
#include <map>
#include <string>
int main() {
std::map<std::string, int> scores;
// nobody has played yet — just checking
if (scores["alice"] == 0)
std::cout << "alice hasn't scored\n";
if (scores["bob"] == 0)
std::cout << "bob hasn't scored\n";
if (scores["carol"] == 0)
std::cout << "carol hasn't scored\n";
std::cout << "players on record: " << scores.size() << "\n";
}
Run it. How many players end up on record?
Answer
players on record: 3. Three read-only lookups on an empty map left three entries
behind.
Why¶
map::operator[] has no way to say "not found" — it returns a reference to the value
for that key, and a reference must refer to something. So when the key is absent, it
default-inserts one: the value is value-initialized (0 for int) and the new entry
goes into the map, then the reference comes back. That means scores["alice"] == 0 is
true precisely because the lookup just planted a zero — every innocent read is a write.
This insert-on-read is also why operator[] doesn't exist on a const map (entry 42).
-Wall -Wextra says nothing; the code is doing exactly what it was told.
The fix¶
Use a real lookup — [] is for writing:
if (scores.count("alice") == 0) // absent, map untouched
if (scores.find("bob") == scores.end()) // same, and find() hands you the entry
if (!scores.contains("carol")) // C++20, says what it means
int s = scores.at("dave"); // read-only access: throws if absent
Takeaway: map::operator[] never answers "no such key" — it creates the key; look
with find/count/contains, and save [] for when inserting is the point.
Try it: g++ -std=c++17 main.cpp -o demo && ./demo