在使用基本的概念管理例外狀況
本主題討論 managed 應用程式中處理的例外狀況。 也就是以編譯的應用程式**/clr**編譯器選項。
本主題內容
擲回例外狀況下 /clr
Try/Catch 區塊的 CLR 擴充
備註
如果使用編譯**/clr**選項,您可以處理 CLR 例外狀況,以及標準 C++ 例外處理和結構化的例外處理 (SEH)。 CLR 例外狀況是由 managed 型別所擲回任何例外狀況。 System::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;
}
Try/Catch 區塊的 CLR 擴充
相同試/攔截區塊結構可用來攔截 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 );
}
}
}
Output
In 'catch(CMyClass& catchC)'
2
In 'catch(MyStruct^ catchException)'
11
C + + 物件的復原順序
回溯,就會發生的任何具有解構函式的作品,執行階段之間的堆疊上擲回的函式,並處理函式的 C++ 物件。 因為 CLR 型別在堆積上配置,回溯不適用於它們。
擲回的例外狀況的事件順序如下所示:
執行階段查核會查詢適當的 catch 子句,或者如果是 SEH,堆疊除了 SEH,攔截例外狀況篩選條件。 Catch 子句會先搜尋語彙的順序,並以動態方式循列呼叫堆疊。
一旦找到正確的處理常式時,堆疊會回溯至該點。 每個函式呼叫堆疊上,其區域物件的解構和 __finally 區塊執行,大部分從巢狀游標向外拖拉。
當堆疊回溯之後,便會執行 catch 子句。
攔截未受管理的型別
擲回的未受管理的物件型別時,它會包裝的例外狀況型別的 System::Runtime.InteropServices::SEHException。 當搜尋適當的攔截子句中,有兩個可能的情況。
如果原生的 C++ 型別,會解除包裝例外狀況,而且相較於發生的型別。 這項比較讓以一般方式攔截的原生 C++ 型別。
不過,如果攔截 的型別子句 SEHException 或任何其基底類別會先檢查,則子句會攔截的例外狀況。 因此,您應該將所有的 catch 子句任何 catch 子句的 CLR 型別之前,先攔截原生 C++ 型別。
請注意
catch(Object^)
和
catch(...)
兩者會攔截任何擲回的型別,包括 SEH 例外狀況。
如果未受管理的型別被 catch(Object^),它不會損壞擲回的物件。
當擲回,或攔截不受管理的例外狀況時,我們建議您採用 /EHsc 編譯器選項,而不是**/EHs或/EHa**。