Podstawowe pojęcia związane z używaniem wyjątków zarządzanych

W tym temacie omówiono obsługę wyjątków w aplikacjach zarządzanych. Oznacza to, że aplikacja skompilowana z opcją kompilatora /clr .

W tym temacie

Uwagi

Jeśli kompilujesz z opcją /clr , można obsługiwać wyjątki CLR, a także klasę standardową Exception zapewnia wiele przydatnych metod przetwarzania wyjątków CLR i jest zalecane jako klasa podstawowa dla klas wyjątków zdefiniowanych przez użytkownika.

Przechwytywanie typów wyjątków pochodzących z interfejsu nie jest obsługiwane w / clr. Ponadto środowisko uruchomieniowe języka wspólnego nie zezwala na przechwytywanie wyjątków przepełnienia stosu; wyjątek przepełnienia stosu zakończy proces.

Aby uzyskać więcej informacji na temat różnic w obsłudze wyjątków w zarządzanych i niezarządzanych aplikacjach, zobacz Różnice w zachowaniu obsługi wyjątków w obszarze Rozszerzenia zarządzane dla języka C++.

Zgłaszanie wyjątków w obszarze /clr

Wyrażenie throw języka C++ zostało rozszerzone, aby zgłosić uchwyt do typu CLR. Poniższy przykład tworzy niestandardowy typ wyjątku, a następnie zgłasza wystąpienie tego typu:

// 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;
}

Przed zgłoszeniem należy zaznaczyć pole typu wartości:

// clr_exception_handling_2.cpp
// compile with: /clr /c
value struct MyValueStruct {
   int i;
};

void GlobalFunction() {
   MyValueStruct v = {11};
   throw (MyValueStruct ^)v;
}

Bloki try/catch dla rozszerzeń CLR

Tej samej try/catch struktury bloków można użyć do przechwytywania zarówno clR, jak i wyjątków natywnych:

// 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 );
      }
   }
}

Dane wyjściowe

In 'catch(CMyClass& catchC)'
2
In 'catch(MyStruct^ catchException)'
11

Kolejność odwijania dla obiektów C++

Odwijanie występuje dla wszystkich obiektów języka C++ z destruktorami, które mogą znajdować się w stosie czasu wykonywania między funkcją throwing i funkcją obsługi. Ponieważ typy CLR są przydzielane na stercie, odwijanie nie ma zastosowania do nich.

Kolejność zdarzeń dla wyjątku zgłaszanego jest następująca:

  1. Środowisko uruchomieniowe przeprowadzi stos w poszukiwaniu odpowiedniej klauzuli catch lub w przypadku SEH, z wyjątkiem filtru SEH, aby przechwycić wyjątek. Klauzule catch są wyszukiwane najpierw w kolejności leksykalnej, a następnie dynamicznie w dół stosu wywołań.

  2. Po znalezieniu poprawnego programu obsługi stos jest w tym momencie niezgarnięty. Dla każdego wywołania funkcji na stosie jego obiekty lokalne są zdestrukturowane, a bloki __finally są wykonywane z większości zagnieżdżonych na zewnątrz.

  3. Po odłączeniu stosu jest wykonywana klauzula catch.

Przechwytywanie typów niezarządzanych

Gdy zgłaszany jest niezarządzany typ obiektu, jest on owinięty wyjątkiem typu SEHException. Podczas wyszukiwania odpowiedniej catch klauzuli istnieją dwie możliwości.

  • Jeśli napotkano natywny typ języka C++, wyjątek jest niezapisany i porównywany z napotkanym typem. To porównanie umożliwia złapanie natywnego typu C++ w normalny sposób.

  • Jeśli jednak najpierw zostanie zbadana klauzula catch typu SEHException lub dowolna z jej klas bazowych, klauzula przechwyci wyjątek. Dlatego należy najpierw umieścić wszystkie klauzule catch, które przechwytują natywne typy języka C++ przed wszelkimi klauzulami catch typów CLR.

Należy pamiętać, że

catch(Object^)

oraz

catch(...)

będzie przechwytywać każdy zgłoszony typ, w tym wyjątki SEH.

Jeśli niezarządzany typ jest przechwytywany przez catch(Object^), nie spowoduje to zniszczenia zgłaszanego obiektu.

Podczas zgłaszania lub przechwytywania niezarządzanych wyjątków zalecamy użycie opcji /EHsc kompilatora zamiast /EHs lub /EHa.

Zobacz też

Obsługa wyjątków
safe_cast
Obsługa wyjątków