2014-01-25 68 views
1

我發現了一個非常非常奇怪的行爲,我從未見過。 我正在處理一個複雜的VS2005 C++項目。當拋出異常時,析構函數沒有執行(沒有堆棧展開)

class Tester 
{ 
public: 
    Tester() 
    { 
     TRACE("Construct Tester"); 
    } 
    ~Tester() 
    { 
     TRACE("~Destruct Tester"); 
    } 
}; 

void Thrower() 
{ 
    Tester X; 
    throw std::exception("Booom"); 
} 

當調用Thrower()時,您期望在跟蹤輸出中看到什麼? 測試器是否構建並在堆棧展開時被破壞?

至少我認爲,但測試人員的析構函數從來沒有被調用!

不可能!!!?!?!

這是Visual Studio中的錯誤嗎?

我搜索了很多,但沒有在Stackoverflow上找到答案。

回答

1

我花了整整一天的時間來找出問題所在。

現在我必須更深入地解釋我在做什麼。 我有一個編譯成LIB文件的C++代碼。上面的代碼(Tester和Thrower)位於這個簡單的C++ LIB文件中。

而我有另一個C++代碼編譯成與此LIB文件鏈接的託管C++ DLL。所以最後兩個代碼都在同一個DLL中。我設法調用在LIB文件中的代碼這樣的包裝函數:

ManagedWrapper() 
{ 
    try 
    { 
     Thrower(); 
    } 
    catch (std::exception& e) 
    { 
     throw new System::Exception(e.what()); 
    } 
} 

這確實工作。 使用此代碼我有內存泄漏和未關閉的網絡套接字。 Thrower中的堆棧未解開。

這樣做的原因是在達到捕獲之前不會發生堆疊展開。但是當抓住另一個圖書館而不是扔掉堆棧沒有解開。 DLL不知道如何在LIB文件中展開堆棧(儘管兩者最終都編譯到同一個DLL中!!)

但是我發現了一個非常簡單的解決方案。

在LIB文件中,我必須像這樣在ManagedWrapper()和Thrower()之間添加一箇中間函數。代碼看起來愚蠢,但它解決了這個問題:

Catcher() 
{ 
    try 
    { 
     Thrower(); 
    } 
    catch(...) // unwind HERE 
    { 
     throw; 
    } 
} 

重要的是,這捕手必須在異常被拋出的LIB文件坐。當捕獲異常時,堆棧被解開,然後將異常重新引發到託管包裝器。

有時看起來很愚蠢的代碼非常聰明!

摘要:永遠不要忘記,必須始終在引發異常的同一個庫中捕獲異常。如果他們跨越圖書館邊界,則會遇到嚴重問題。

+0

如果這是Visual Studio中的一個錯誤,那麼應該在互聯網上有任何信息。但我找不到任何東西。但是,也許你是對的。 – Elmue

相關問題