Safe and const-correct std::map Access in C++ STL

The Standard Template Library std::map[] operator will create and return a new entry if passed a key that does not already exist in the map.
This means that you cannot use this operator when you do not want to create a new entry (i.e., you expect the key-value pair to already exist in the map), or in a const context (i.e., in a const method or when using a const object).
Instead, in these situations, you need to first pull a (const) iterator using std::map.find(), and then check to see if its value equals std::map.end(), and only if not proceed with referencing the result.

This means that instead of, for example:

    double v = split_lengths[s];

You need to:

    std::map::const_iterator it = split_lengths.find(s);
    if (it != split_lengths.end()) {
        // do what you want ... finally!
    } else {
        // raise exception
    }

Yup. This is a pain. Victorian kitchen cooking, indeed.

The new C++0x supplies an std::map.at() method, which throws a std::out_of_range exception if the value is not found.
If I am going to still be programming in C++ in a couple of decades when this version becomes widespread enough, that would be the way to go. In the meantime, however, the following template makes life a little easier:

template
const typename T::value_type::second_type& map_at(const T& container,
        const typename T::value_type::first_type key) {
    typename T::const_iterator it = container.find(key);
    if (it == container.end()) {
        throw std::out_of_range("Key not found");
    }
    return it->second;
}

Now a safe yet succint (in C++/STL terms) way of getting items out of a map is:

    double v = map_at(split_lengths, s);

Bringing the Victorian kitchen into the Edwardian era one new-fangled gadget at a time.

Leave a Reply

Your email address will not be published. Required fields are marked *