c++exceptionstlstdmap

Unable to catch unhandled exception while using std::map


I am trying to make use of operator[] in std::map to read elements using keys.

But when I am trying to access an invalid key it is throwing an exception which I am not able to catch using try-catch block .

Here is the code I am using:

class MapElement
{
public:
    int a;
    char c;
};

int main()
{
     MapElement m1, m2, m3;
     m1.a = 10; m1.c = 'a';
     m2.a = 20; m2.c = 'b';
     m3.a = 30; m3.c = 'c';

     map<char, MapElement*> Mymap;
     map<char, MapElement*>::iterator iter = Mymap.begin();
     Mymap.insert(iter, std::pair<int, MapElement*>('1', &m1));
     Mymap.insert(iter, std::pair<int, MapElement*>('1', &m2));
     cout << Mymap['1']->a;

     try
     {
         cout << Mymap['2']->a;
     }
     catch (exception e)
     {
         cout << e.what();
     }
     catch (...)
     {
         cout << "unknown error";
     }
}

How can I handle this exception?


Solution

  • The problem is being caused by std::map::operator[] creating a new entry for a key that does not exist:

    Returns a reference to the value that is mapped to a key equivalent to key, performing an insertion if such key does not already exist.

    In this case, the value is a pointer which will not be pointing to a valid MapElement. This is not a runtime failure but a programmer error and is causing undefined behaviour. Even it is possible to catch this type of error it should not be caught in a way that would permit the program to continue as the program may exhibit other unexpected behaviour.

    Use std::map::at() if your compiler supports c++11:

    try
    {
        std::cout<< Mymap.at('2') << std::endl;
    }
    catch (std::out_of_range& const e)
    {
        std::cerr << e.what() << std::endl;
    }
    

    (see http://ideone.com/FR4svY for an example). Otherwise, if your compiler does not support c++11 use std::map::find(), which does not throw an exception but returns std::map::end() if the map does not contain the requested key:

    template <typename K, typename V>
    V& map_at(std::map<K, V>& a_map, K const& a_key)
    {
        typename std::map<K, V>::iterator i = a_map.find(a_key);
        if (a_map.end() == i)
        {
            throw std::out_of_range("map_at()");
        }
        return i->second;
    }
    
    try
    {
        std::cout<< map_at(Mymap, '2') << std::endl;
    }
    catch (std::out_of_range& const e)
    {
        std::cerr << e.what() << std::endl;
    }
    

    (see http://ideone.com/lIkTD3 for example).