Урок №187. Функциональный try-блок

  Юрий  | 

    | 

  Обновл. 16 Дек 2018  | 

 878

Функционала блоков try и catch достаточно в большинстве случаев, но есть одна конкретная ситуация, в которой их стандартного функционала недостаточно. Рассмотрим следующий код:

В программе выше дочерний класс B вызывает конструктор родительского класса A, который генерирует исключение (при успешном выполнении условия). Поскольку объект b создается в блоке try функции main(), то если A выбросит исключение, блок try функции main() словит его и передаст обработчику catch (int). Следовательно, результат выполнения этой программы:

Oops!

Но что, если нам нужно обрабатывать исключение внутри класса B? Вызов конструктора родительского класса A происходит через список инициализации членов, перед выполнением тела конструктора класса B. Поэтому использовать стандартный блок try здесь не получится.

В этой ситуации мы должны использовать слегка модифицированный блок try — функциональный try-блок (или еще «функциональный блок try»).

Функциональный try-блок

Функциональный try-блок используется для установления обработчика исключений вокруг тела всей функции, а не лишь её части (блока кода).

Синтаксис немного сложен для описания, поэтому рассмотрим всё на примере:

Результат выполнения программы выше:

Construction of A failed
Oops!

Рассмотрим эту программу более подробно.

Во-первых, обратите внимание на добавление ключевого слова try перед списком инициализации членов класса класса B. Это означает, что всё, что находится после этого ключевого слова (вплоть до конца функции) рассматривается как часть блока try.

Во-вторых, обратите внимание, что блок catch находится на том же уровне отступа, что и вся функция. Любое исключение, выброшенное между ключевым словом try и концом тела конструктора, будет обработано этим же блоком catch.

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

В программе выше, поскольку мы явно не генерируем исключение внутри блока catch, исключение повторно генерируется и передается caller-у на уровень выше, т.е. функции main(). Блок catch функции main() ловит и обрабатывает исключение и мы получаем Oops!.

Хотя функциональные try-блоки также могут использоваться и с обычными функциями, которые не являются методами класса, это не распространенная практика, так как случаев, где они могут быть полезны очень и очень мало. Они почти всегда используются только с конструкторами!

Не используйте функциональный try-блок для очистки памяти


Если операция создания объекта неуспешна, то деструктор класса не вызывается. Следовательно, у вас может возникнуть соблазн использовать функциональный try-блок для очистки частично выделенной памяти классом. Однако обращение к членам объекта, который не создался, считается неопределенным поведением, так как объект уже «мертв» до начала выполнения блока catch. Это означает, что вы не можете использовать функциональный try-блок для выполнения очистки памяти класса.

Итого

Функциональные try-блоки полезны в основном для записывания ошибок в лог-файл перед их передачей на уровень выше в стеке вызовов или для изменения типа выбрасываемого исключения.


Оценить статью:

Звёзд: 1Звёзд: 2Звёзд: 3Звёзд: 4Звёзд: 5 (13 оценок, среднее: 4,77 из 5)
Загрузка...

Добавить комментарий

Ваш E-mail не будет опубликован. Обязательные поля помечены *