2013-11-25 54 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 
}