2012-09-22 44 views
13

今天,我發現在catch塊的錯誤失去異常類型:重新拋出從catch塊的異常時

catch (const exception& e){ 
    // do something 
    // throw e; <-- bug! 
    throw; // <-- right thing to do 
} 

基本上,如果我重新拋出異常e明確,我得到一個新的std::exception重建,在事實上,來自what()方法的消息是默認的std::string,而不是我自定義的內置消息。

是什麼解釋?我認爲throw;只是throw ExceptionJustCaught;的簡寫。

+0

這是價值和參考之間的差異。 –

+0

這是一個非常重要的概念,經常被忽視(在我看來,這是一個棘手的語法問題,編譯時至少應該是一個警告。)。偉大的問題! 「參考」爲 – NHDaly

回答

13

異常對象有點特別。它們被建造在一個特殊的地方,它們的壽命取決於它們被捕獲的捕獲塊。

如果你說throw e;,原始異常的壽命在catch塊的結尾結束,你是通過複製e,從而產生一個經典切片問題拋出一個新的異常:由於e是一個多態參考對於其動態類型通常比std::exception派生更多的對象,最終會切斷對象的派生部分。

相比之下,throw;是重新激活原來的異常,因此它不再是抓到了特別聲明,它的壽命確實在塊結束結束了。事實上,如果你通過非常量引用來捕獲,你可以不斷修改異常對象並重新拋出,並將狀態改變傳遞給較低的catch塊。但請記住,重新排列不同於拋出新的異常!

8

只是一個throw通過引用引發當前異常。 throw e拷貝構造一個拋出的新異常。這與return的工作方式大致相同。

+0

。確切的說,這不應該失去'what()'的正確實現,它承載着我的消息。 –

+0

您可以發佈一個完整的,可編譯的代碼示例,並用儘可能少的線條來演示該問題嗎?很可能,您的拷貝構造函數不保留消息。 –

+0

Kerrek的答案看起來是正確的,我懷疑是有一個切片問題,所以我不會編輯問題,因爲我認爲這是正確的答案。也許大衛的說法是正確的,但說實話,這還不夠清楚。 –