Skip to content

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

Open in Compiler Explorer ↗ Quiz this entry