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?
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).