2013-11-25 52 views
2

我正在尝试使用operator[] in std::map来使用键读取元素。 但是,当我试图访问一个无效的密钥它是抛出一个异常,我无法赶上使用try - catch块。这里是我使用的代码:使用std :: map时无法捕获未处理的exence :: map

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

int main() 
{ 
    MapElement m1,m2,m3; 
    map <char ,MapElement*> Mymap; 
    m1.a =10;m1.c = 'a'; 
    m2.a =20;m2.c ='b'; 
    m3.a =30;m3.c ='c'; 

    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"; 
    } 
} 

我该如何处理这个异常?

回答

5

的问题是由std::map::operator[]创建密钥的新条目不存在引起的:

返回到被映射到键等同于键的值的基准,如果这样进行的插入键尚不存在。

在这种情况下,该值是一个指针,它不会指向有效的MapElement。 这不是运行时失败,而是程序员错误,并导致未定义的行为。即使有可能发现这种类型的错误,它也不应该以一种允许程序继续执行的方式来捕捉,因为程序可能会出现其他意想不到的行为。

使用std::map::at()如果你的编译器支持C++ 11:

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

(见http://ideone.com/FR4svY的例子)。 否则,如果你的编译器不支持C++ 11使用 std::map::find(),不抛出异常,但返回std::map::end()如果地图不包含请求的密钥:

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; 
} 

(见http://ideone.com/lIkTD3为例)。

+0

我试过的std :: out_of_range,但它仍然没有捕捉异常。我在代码块和Visual Studio中都尝试过。 – kernel

+0

@kernel,工作正常:http://ideone.com/FR4svY – hmjd

2

问题在于你在这里取消引用了一个空指针,因为用一个不存在的键调用operator[]导致用该键创建一个新元素,并且创建了一个值初始化值类型(在这种情况下,空MapElement*):

cout<<Mymap['2']->a; // The error is to call ->a, not Mymap['2'] 

这不会引发异常,它是未定义的行为。你可以做的是调用引发异常,而不是一个方法:

MapElement* m = Mymap.at('2'); // throws if there is no '2' element 
cout << m->a; 

这里,调用at()会在出现与关键'2'没有元素抛出。

2

我建议你使用find方法,并将其与地图的结束比较喊得unexisting键:

map<char,MapElement*>::iterator iter = Mymap.find('2'); 
if (iter != Mymap.end()) { 
    // do something if the key exist 
} else { 
    // do anythig if the key was not founded 
}