Обработка исключительных ситуаций

В программе можно объявить блок, в котором мы будем отслеживать исключительные ситуации с помощью операторов try и catch :

try { ...}catch (тип_исключительной_операции){ ...}Если внутри блока try возникла исключительная ситуация, то она первым делом передается в оператор catch . Тип исключительной ситуации – это тип аргумента throw . Если тип исключительной ситуации совместим с типом аргумента catch , выполняется блок catch . Тип аргумента catch совместим, если он либо совпадает с типом ситуации, либо является одним из ее базовых типов. Если тип несовместим, то происходит описанный выше откат вызовов, до тех пор, пока либо не завершится программа, либо не встретится блок catch с подходящим типом аргумента.

В блоке catch происходит обработка исключительной ситуации.

Ссылка на аргумент throw передается в блок catch . Этот блок гасит исключительную ситуацию. Во время обработки в блоке catch можно создать либо ту же самую исключительную ситуацию с помощью оператора throw без аргументов, либо другую, или же не создавать никакой. В последнем случае исключительная ситуация считается погашенной, и выполнение программы продолжается после блока catch .

С одним блоком try может быть связано несколько блоков catch с разными аргументами. В этом случае исключительная ситуация последовательно "примеряется" к каждому catch до тех пор, пока аргумент не окажется совместимым. Этот блок и выполняется. Специальный вид catch

catch (...)совместим с любым типом исключительной ситуации. Правда, в него нельзя передать аргумент.

Аббревиатура SEH - это Structured exception handling. Этот механизм обработки исключений отличается от обработки исключений в С++. Он разработан специально для Windows и реализован в Visual C++. Естественно, как у каждого альтернативного метода у него есть свои плюсы и минусы. Помните мы говорили про исключения С++, что если они выбрасываются, то при обработке исключений SEH они возбуждаются. Так вот выбрасывание исключения всегда производится программным путем, а возбуждении исключения может быть программным или аппаратным. Когда возбуждается исключительная ситуация задается ее код, который можно рассматривать как тип фильтр может обрабатывать код, чтобы по- разному организовать обработку. SEH предоставляет два механизма.

  • Обработку завершения termination handling
  • Обработку исключения exception handling

Общая идея обработки похожа. Код заключается в блок обработки __try, но в отличии от C++ обработки дальше может следовать один из двух блоков обработки, это либо __finaly либо __except блок. Синтаксически это оформляется так:

#include "stdafx.h"void main(){ __try { } __finally { }}

Исключение может возбуждаться в теле __try, как внутри блока так и в функциях внутри его явно или неявно вызванных. Главная особенность __finally в том, что его работа не зависит от реализации блока __try, так как он обязательно должен выполниться в случае непредвиденной ситуации, закрыть файлы, освободить память и все там такое.

Фильтрующее выражение должно принимать одно из трех значений:

EXCEPTION_EXECUTE_HANDLER

EXCEPTION_CONTINUE_SEARCH

EXCEPTION_CONTINUE_EXECUTION

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

SEH предоставляет обработчики двух типов:

  • Обработка завершения
  • Обработка исключений

Обработчик завершения гарантирует, что некий код будет выполнен независимо от того, как завершиться другой блок:

__try { } _finally // обработчик завершения { }

Это очень похоже на синтаксис C++ исключений. С помощью ключевого слова __try - защищаем участок кода. Теперь мы можем обрабатывать все события, которые в нем происходят.

В приведенном примере гарантируется, что блок __finaly будет выполнен независимо от того, как будет осуществлен выход из блока __try: по ошибке или с помощью операторов перехода return, goto. Даже если программист использует longjump – блок __finaly будет все равно выполнен.

Блок __finaly можно использовать для освобождения ресурсов, чтобы избежать из утечки.

Как видите – преимущества налицо. Надо только иметь ввиду, что локальная раскрутка требует значительного времени. Поэтому необоснованное использование этой конструкции может привести к существенному падению производительности. Наибольшие потери происходят если блок __try завершается преждевременно. В других случаях затраты времени минимальны.

Для уменьшения накладных расходов от преждевременного завершения существует ключевое слово _leave. Его можно использовать внутри блока __try. Когда компилятор встречает это слово – происходит выход из блока __try и выполнение блока __finaly. Т.е. его можно рассматривать как переход на закрывающуюся скобку блока __try.В выражении фильтра можно вызвать функцию GetExceptionInformation() или GetExceptionCode () . Первая из них возвращает указатель на структуру EXCEPTION_POINTERS, которая содержит детальную ин-формацию об исключении; вторая возвращает только кодовое значение для исключения.

Наши рекомендации