使用 Managed 例外狀況中的基本概念
本主題討論受控應用程式中的例外狀況處理。 也就是說,使用 /clr 編譯程式選項編譯的應用程式。
本主題內容
備註
如果您使用 /clr 選項進行編譯,則可以處理 CLR 例外狀況,以及標準Exception類別提供許多有用的方法來處理 CLR 例外狀況,並建議做為使用者定義例外狀況類別的基類。
/clr 下不支援擷取衍生自 介面的例外狀況類型。 此外,Common Language Runtime 不允許您攔截堆棧溢位例外狀況;堆疊溢位例外狀況將會終止進程。
如需 Managed 和 Unmanaged 應用程式中例外狀況處理差異的詳細資訊,請參閱 managed Extensions for C++ 的例外狀況處理行為差異。
在 /clr 下擲回例外狀況
C++ throw 表達式會擴充為擲回 CLR 類型的句柄。 下列範例會建立自定義例外狀況類型,然後擲回該類型的實例:
// clr_exception_handling.cpp
// compile with: /clr /c
ref struct MyStruct: public System::Exception {
public:
int i;
};
void GlobalFunction() {
MyStruct^ pMyStruct = gcnew MyStruct;
throw pMyStruct;
}
在擲回之前,必須先 Boxed 實值型別:
// clr_exception_handling_2.cpp
// compile with: /clr /c
value struct MyValueStruct {
int i;
};
void GlobalFunction() {
MyValueStruct v = {11};
throw (MyValueStruct ^)v;
}
嘗試/攔截 CLR 延伸模組的區塊
相同的 try
/catch
區塊結構可用於擷取 CLR 和原生例外狀況:
// clr_exception_handling_3.cpp
// compile with: /clr
using namespace System;
ref struct MyStruct : public Exception {
public:
int i;
};
struct CMyClass {
public:
double d;
};
void GlobalFunction() {
MyStruct^ pMyStruct = gcnew MyStruct;
pMyStruct->i = 11;
throw pMyStruct;
}
void GlobalFunction2() {
CMyClass c = {2.0};
throw c;
}
int main() {
for ( int i = 1; i >= 0; --i ) {
try {
if ( i == 1 )
GlobalFunction2();
if ( i == 0 )
GlobalFunction();
}
catch ( CMyClass& catchC ) {
Console::WriteLine( "In 'catch(CMyClass& catchC)'" );
Console::WriteLine( catchC.d );
}
catch ( MyStruct^ catchException ) {
Console::WriteLine( "In 'catch(MyStruct^ catchException)'" );
Console::WriteLine( catchException->i );
}
}
}
輸出
In 'catch(CMyClass& catchC)'
2
In 'catch(MyStruct^ catchException)'
11
C++ 物件的回溯順序
擲回函式與處理函式之間可能位於運行時間堆疊上之解構函式的任何C++對象都會發生回溯。 由於 CLR 類型是在堆積上配置,因此回溯不適用於它們。
擲回例外狀況的事件順序如下:
運行時間會逐步引導堆疊尋找適當的 catch 子句,或在 SEH 的情況下,除了篩選 SEH 之外,擷取例外狀況。 Catch 子句會先依語匯順序搜尋,然後動態向下搜尋呼叫堆棧。
找到正確的處理程式之後,堆疊就會復原到該點。 對於堆疊上的每個函式呼叫,其本機對象都會被解構,而且會從大部分巢狀向外執行__finally區塊。
一旦堆疊解除復原,就會執行 catch 子句。
擷取 Unmanaged 類型
擲回 Unmanaged 物件類型時,它會以 類型的 SEHException例外狀況包裝。 搜尋適當的 catch
子句時,有兩種可能性。
如果遇到原生C++類型,則例外狀況會解除包裝,而且與所遇到的類型相較之下。 這項比較可讓原生C++類型以正常方式攔截。
不過,如果
catch
先檢查 SEHException 類型的子句或其任何基類,子句將會攔截例外狀況。 因此,您應該將所有 catch 子句放在 CLR 型別的任何 catch 子句之前,先攔截原生C++型別。
請注意:
catch(Object^)
及
catch(...)
兩者都會攔截任何擲回的類型,包括 SEH 例外狀況。
如果 catch(Object^) 攔截了 Unmanaged 類型,則不會終結擲回的物件。
擲回或攔截 Unmanaged 例外狀況時,建議您使用 /EHsc 編譯程序選項,而不是 /EHs 或 /EHa。