• Допустимо преобразование из неконстантного типа в константный, т.е. переданный неконстантный объект исключения может быть обработан блоком catch
, ожидающим ссылку на константный.
• Допустимо преобразование из производного типа в базовый.
• Массив преобразуется в указатель на тип массива; функция преобразуется в соответствующий указатель на тип функции.
Никакие другие преобразования при поиске соответствующего обработчика недопустимы. В частности, невозможны ни стандартные арифметические преобразования, ни преобразования, определенные для классов.
catch
с типами, связанными наследованием, обработчики для более производных типов следует располагать прежде наименее производных.
Вполне возможна ситуация, когда один блок кода catch
(обработчик) не сможет полностью обработать исключение. После некоторых корректирующих действий обработчик может решать, что это исключение следует обработать в функции, которая расположена далее по цепи вызовов. Обработчик может передавать исключение другому, внешнему обработчику, который принадлежит функции, вызвавшей данную. Это называется throw
, после которого нет ни имени типа, ни выражения.
throw;
Пустой оператор throw
может присутствовать только в обработчике или в функции, вызов которой осуществляется из обработчика (прямо или косвенно). Если пустой оператор throw
встретится вне обработчика, будет вызвана функция terminate()
.
Повторная передача не определяет нового исключения; по цепочке передается текущий объект исключения.
Обычно обработчик вполне может изменить содержимое своего параметра. Если после изменения своего параметра обработчик повторно передаст исключение, то эти изменения будут переданы далее, только если параметр обработчика объявлен как ссылка:
catch (my_error &eObj) { //
eObj.status = errCodes::severeErr; //
throw; //
//
} catch (other_error eObj) { //
eObj.status = errCodes::badErr; //
throw; //
//
}
Иногда необходимо обрабатывать все исключения, которые могут произойти, независимо от их типа. Обработка каждого возможного исключения может быть проблематична: иногда неизвестно, исключения каких типов могут быть переданы. Даже когда все возможные типы известны, предоставление отдельной директивы catch
для каждого возможного исключения может оказаться весьма утомительным. Для обработки всех исключений в объявлении исключения используется многоточие. Такие обработчики, называемые catch(...)
. Такая директива соответствует исключениям любого типа.
Обработчик catch(...)
зачастую используется в комбинации с выражением повторной передачи. Обработчик осуществляет все локальные действия, а затем повторно передает исключение:
void manip() {
try {
//
} catch (...) {
//
throw;
}
Директива catch(...)
применяется самостоятельно или в составе нескольких директив catch
.
catch(...)
используется в комбинации с другими, она должна располагаться последней. Любой обработчик, следующий за обработчиком для всех исключений, никогда не будет выполнен.
Упражнение 18.4. Заглянув вперед в иерархию наследования на рис. 18.1, объясните, что неправильно в следующем блоке try
. Исправьте его:
try {
// использовать стандартную библиотеку С++
} catch(exception) {
// ...
} catch(const runtime_error &re) {
// ...
} catch(overflow_error eobj) { /* ... */ }
Упражнение 18.5. Измените следующую функцию main()
так, чтобы обрабатывались исключения любых типов, представленных на рис. 18.1:
int main() {
// использовать стандартную библиотеку С++
}