2012-01-18 16 views
0

我剛問過this question。簡而言之,當你從一個win32定時器回調中拋出時,這個異常不會出現在任何地方。它似乎在某處被Windows悄悄地處理。爲什麼我的析構函數在從win32定時器回調中拋出時調用?

好吧,這是一個問題。問題的另一方面是當拋出這個異常時,析構函數似乎不會被調用。在下面的代碼中,對於CFoo的std::vector,輸出「〜CFoo」唯一的時間是當GetFooVect中的臨時對象被破壞並且rValue被複制到fooVect時。 fooVect的內容不會被破壞。

這是我最糟糕的噩夢。我非常使用RAII。我非常依賴我的析構函數進行適當的清理。

class CFoo 
{ 
public: 
    ~CFoo() {printf(__FUNCTION__ "\n");} 
}; 

std::vector<CFoo> GetFooVect() 
{ 
    std::vector<CFoo> rValue; 
    rValue.push_back(CFoo()); 
    rValue.push_back(CFoo()); 
    rValue.push_back(CFoo()); 
    return rValue; 
} 

VOID CALLBACK Timer(HWND hwnd, 
    UINT uMsg, 
    UINT_PTR idEvent, 
    DWORD dwTime) 
{ 
    // My destructors aren't called? 
    std::vector< CFoo> fooVect = GetFooVect(); 

    // I'm destroyed 
    CFoo aFoo; 

    throw FooExcept(); 
    printf("Also Here\n"); 
} 

我試着通過簡單地拋出/捕獲C++異常重塑這種(即去除的Win​​32計時器回調變量)和Cfoo的的自毀蠻好的載體。出於某種原因,析構函數在這裏不會被稱爲向量中的東西。是什麼賦予了?這是否有一個合理的解釋,或者這是否奇怪,或兩者兼而有之?

回答

6

您絕對不應該允許異常在C API邊界傳播(如SetTimer回調)。 C代碼(和Windows API函數)對C++語言異常一無所知。你不能依靠這樣的代碼來傳播你的異常。

您的回調函數應該在返回並正確處理異常之前捕獲所有C++語言異常。如果您需要以某種方式將例外與您的其他應用程序進行通信,則需要自行完成。

(這裏的其他人可能會詳細解釋在這種情況下發生了什麼,但簡短的回答是,您不能依賴C代碼在存在C++語言異常的情況下做正確的事情,因爲它不知道什麼是C++語言異常。)

+0

+1:永遠不會從Win32回調或針對該問題的COM接口方法拋出異常;這樣做基本上是未定義的行爲。如果您在其中任何一箇中使用異常,請在返回之前捕獲*所有內容*,然後返回正常的返回碼。如果你希望異常傳播得更高,那麼你可以在其他地方保存狀態,通過API正常返回,然後檢查錯誤並在控制返回到自己的代碼時再次拋出... – BrendanMcK 2012-01-18 01:52:27

+0

可能這裏發生了什麼是C++運行時在其異常實現中使用較低級的結構化異常處理(SEH)功能,而Win32中的代碼也使用SEH,但出於其自身目的干擾C++運行時。它比C++少C++,因此實現異常的C++運行時僅對編譯的代碼或編譯器附帶的庫具有「管轄權」; Win32代碼模塊和DLL是他們自己的宇宙。同樣,你只能在你自己的代碼中使用C++ RTTI,而不能使用從Win32或COM中獲取的任意對象。 – BrendanMcK 2012-01-18 02:03:07

+0

要清楚,因此析構函數在運行時找到一個C++ catch塊時纔會執行 - 當然,在定時器回調之上的callstack中沒有更高的析構函數。 – 2012-01-18 16:42:17

相關問題