1 min read

Beware map indexing in C++

Beware: If you index a C++ map with a key not in the map (e.g. map[key]), it won't raise an error — it'll just construct, insert and return a default value. If the value type has no default constructor, the program will segfault.

This is usually not what I want. I mostly write Python and I usually want Python's behavior: Raise a KeyError if the key isn't in the map. I've been bitten by C++'s behavior twice this year: I used indexing, and then the program I am working on mysteriously misbehaved, and eventually I tracked it down to an indexing expression like this.

I'm planning to switch to map.at(key) as a default for new code. The .at() method raises std::out_of_range when the key isn't in the map.

It's only a default, because the error reporting for .at() sucks. The std::out_of_range error message doesn't include the key. This makes enough sense for the standard library, because stringifying the key may be impossible or impractical. I'm also not sure it's possible/practical in C++ to make an exception polymorphic in the key type. It's understandable—but we can do better.

This where wrapper functions come in handy. One can define a get_value_safe(map, key) that wraps .at() to do something more reasonable for the application for a specific key type, or polymorphically as a template. For example, the wrapper might exit the program with an error message, or throw an exception that includes the key. Defining this wrapper is annoying—but in some cases it's worth it. Knowing the missing key makes debugging an error far faster.