Поделиться через


Основные принципы использования управляемых исключений

В этом разделе рассматривается обработка исключений в управляемых приложениях. То есть приложение, скомпилированное с параметром компилятора /clr .

В этом разделе

Замечания

При компиляции с параметром /clr можно обрабатывать исключения СРЕДЫ CLR , а также стандартный Exception класс предоставляет множество полезных методов обработки исключений CLR и рекомендуется в качестве базового класса для определяемых пользователем классов исключений.

Перехват типов исключений, производных от интерфейса, не поддерживается в / clr. Кроме того, среда CLR не позволяет перехватывать исключения переполнения стека; Исключение переполнения стека завершит процесс.

Дополнительные сведения о различиях в обработке исключений в управляемых и неуправляемых приложениях см. в разделе "Различия в поведении обработки исключений в управляемые расширения для C++".

Создание исключений в /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;
}

Перед созданием нужно задать тип значения:

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

Одну и ту же 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.

Перехват неуправляемых типов

При возникновении неуправляемого типа объекта он упаковывается за исключением типа SEHException. При поиске соответствующего catch предложения существует два варианта.

  • Если обнаружен собственный тип C++, исключение раскроется и сравнивается с обнаруженным типом. Это сравнение позволяет использовать собственный тип C++ обычным образом.

  • Однако если catch предложение типа SEHException или любой из его базовых классов рассматривается сначала, предложение перехватит исключение. Поэтому следует поместить все предложения catch, которые перехватывать собственные типы C++, прежде чем любые предложения catch типов CLR.

Обратите внимание, что

catch(Object^)

и

catch(...)

будет перехватывать любой создаваемый тип, включая исключения SEH.

Если неуправляемый тип перехватывается catch(Object^), он не будет уничтожать создаваемый объект.

При вызове или перехвате неуправляемых исключений рекомендуется использовать параметр компилятора /EHsc вместо /EHs или /EHa.

См. также

Обработка исключений
safe_cast
Обработка исключений