2010-08-12 29 views
5

我聽說從C++庫中拋出異常可能具有潛在的危險性,特別是對於DLL,特別是如果調用代碼和庫是用不同的編譯器編譯的話。有沒有道理呢?只要我堅持靜態庫,它是否安全?請注意,我並不只是在庫內部使用異常,我想把它們深入到調用代碼中:)不安全從靜態鏈接的C++庫中拋出異常?

只是澄清:說我有一個編譯的靜態庫,它定義類Foo這樣的:

class Foo 
{ 
public: 
    // Constructor 
    Foo() 
    { 
     /* ... Do stuff ... */   
     if (stuffwentwrong) 
      throw(123); // We throw an integer error code (to make it simple) 
    } 
}; 

而有些人使用它是這樣的:

try 
{ 
    Foo foo_object; 
} 
catch (int i) 
{ 
    std::cout << "Oh bum. Code: " << i; 
} 

請問這是安全的?

+0

有問題(15年前),這些都已經解決了(除非你正在做的事情時髦像動態加載/全部由自己卸載DLL)。如果你只是直接使用DLL,那麼你應該沒問題。 – 2010-08-12 19:50:54

回答

3

,特別是如果調用代碼和庫與不同的編譯器

您編譯一般不能混用沒有兼容ABI不同的C++編譯器。因此,例如,您不能從MSVC編譯的庫中拋出異常,並嘗試使用GCC捕獲 。

但除此之外,您通常沒有問題。

小記:

MSVC有幾個不兼容的異常模式,不混合。

+0

還有很多其他的細節讓它在一般情況下很危險。例如,如果DLL是用不同版本的CRT編譯的,你將會被搞砸(例如debug vs. release,或者多線程與單線程)。此外,CRT在模塊級別存儲某些狀態,而不是進程級別(例如hModule或內存跟蹤信息),所以當您跨DLL邊界傳輸依賴於CRT的對象時,所有這些事情都可能會失去同步。錯誤是在運行時間,可以是非常微妙的/頭部劃痕。一般來說要避免這一點 – tenfour 2010-08-19 15:48:46

0

您給出的示例應該可以正常工作,但是對於DLL,如果碰巧拋出堆分配的異常,如果DLL的使用者嘗試釋放堆分配的異常,則會崩潰。

3

對於GCC,至少有一種情況可能會導致從GCC生成的共享庫中捕獲異常問題,即默認情況下,當符號可見性爲「hidden」時,忘記從共享庫中導出能力類型。 GCC Visibility Wiki頁面詳細介紹了該問題以及如何防止該問題。

我不確定Windows DLL是否有類似的問題,但似乎很可能。