На этом шаге мы рассмотрим принципы структурной обработки исключений.
Все методы обработки исключений основаны на механизме SEH. Именно обработка исключений является начальным звеном цепи сообщений, ведущей к приложению. Приложения поддерживают SEH с помощью ключевых слов __try, __except и __finally. Блоку __try должен соответствовать либо блок __except, либо __finally, но не оба сразу. Употребляются они следующим образом:
__try { //Код нормального выполнения } __except (filter) { //Здесь перехватываются ошибки, возникающие в блоке try }
Обратите особое внимание на то, что перед этими ключевыми словами стоят два символа подчеркивания. Блок __except выполняется, только когда блок __try вызвал исключение. Если же блок __try закончился успешно, начинают выполняться инструкции, следующие за блоком __except, таким образом приложение его обходит.
С помощью параметра filter определяется, способен ли данный блок __except обработать исключение. Значения этого параметра перечислены в следующей таблице.
Значение | Описание |
---|---|
EXCEPTION_CONTINUE_SEARCH | Блок __except не обрабатывает исключение и передает управление обработчику более высокого уровня |
EXCEPTION_CONTINUE_EXECUTION | Блок __except отвергает исключение, возвращая управление инструкции, вызвавшей исключение |
EXCEPTION_EXECUTE_HANDLER | Выполняется код блока __except |
Такое значение параметра filter, как EXCEPTION_CONTINUE_SEARCH, может Вам показаться странным, ведь при этом блок __except становится бесполезным. Зачем нужен обработчик, который просто повторяет выполнение оператора, вызвавшего исключение? Дело в том, что блок __except обычно вызывает вспомогательную функцию, которая и возвращает значение параметра filter:
__except (GetFilter()) { //Тело блока __except } . . . long GetFilter() { long lFilter; //Определяет соответствующий ошибке параметр filter return lFilter; }
Вспомогательная функция анализирует текущие условия и пытается исправить проблему, вызвавшую исключение. В случае удачи она возвращает EXCEPTION_CONTINUE_EXECUTION, что приводит к игнорированию блока __except и повтору вызвавшей ошибку инструкции блока __try. Однако такой способ обработки сбоев следует использовать с осторожностью, ведь если вспомогательной функции не удастся исправить ошибку, то программа войдет в бесконечный цикл, снова и снова вызывая одно и то же исключение.
Несмотря на то, что ключевое слово __finally является частью SEH, оно имеет мало общего с операционной системой. Оно определяет блок операторов, который гарантированно выполняется по окончании блока __try. Даже если в блоке __try есть операторы RETURN или GOTO, обходящие блок __finally, он будет выполнен до переходов, вызванных этими операторами. Ключевое слово __finally не принимает никаких параметров.
На следующем шаге мы рассмотрим обработку исключений C++.