共用方式為


使用 Managed 例外狀況中的基本概念

本主題討論受控應用程式中的例外狀況處理。 也就是說,使用 /clr 編譯器選項編譯的應用程式。

本主題內容

備註

如果您使用 /clr 選項進行編譯 ,則可以處理 CLR 例外狀況,以及標準 Exception 類別提供許多有用的方法來處理 CLR 例外狀況,並建議做為使用者定義例外狀況類別的基類。

/clr 不支援擷取衍生自 介面的例外狀況類型。 此外,Common Language Runtime 不允許您攔截堆疊溢位例外狀況;堆疊溢位例外狀況將會終止進程。

如需 Managed 和 Unmanaged 應用程式中例外狀況處理差異的詳細資訊,請參閱 C++ Managed Extensions 下的例外狀況處理行為差異。

在 /clr 下擲回例外狀況

C++ 擲回運算式會擴充為擲回 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 類型是在堆積上配置,因此回溯不適用於它們。

擲回例外狀況的事件順序如下:

  1. 執行時間會逐步引導堆疊尋找適當的 catch 子句,或在 SEH 的情況下,除了篩選 SEH 之外,擷取例外狀況。 Catch 子句會先依語彙順序搜尋,然後動態向下搜尋呼叫堆疊。

  2. 找到正確的處理常式之後,堆疊就會復原到該點。 對於堆疊上的每個函式呼叫,其本機物件都會被解構,而且會從大部分巢狀向外執行__finally區塊。

  3. 一旦堆疊解除復原,就會執行 catch 子句。

擷取 Unmanaged 類型

擲回 Unmanaged 物件類型時,它會以 類型的 SEHException 例外狀況包裝。 搜尋適當的 catch 子句時,有兩種可能性。

  • 如果遇到原生 C++ 類型,則例外狀況會解除包裝,而且與所遇到的類型相較之下。 此比較可讓原生 C++ 類型以正常方式攔截。

  • 不過,如果 catch 先檢查 SEHException 類型的 子句或其任何基類,子句將會攔截例外狀況。 因此,您應該將所有 catch 子句放在 CLR 型別的任何 catch 子句之前先攔截原生 C++ 類型。

請注意:

catch(Object^)

catch(...)

兩者都會攔截任何擲回的類型,包括 SEH 例外狀況。

如果 catch(Object^) 攔截了 Unmanaged 類型,則不會終結擲回的物件。

擲回或攔截 Unmanaged 例外狀況時,建議您使用 /EHsc 編譯器選項,而不是 /EHs /EHa

另請參閱

例外狀況處理
safe_cast
例外狀況處理