|
Программирование >> Разработка устойчивых систем
try { программный код. который может генерировать исключения } catch(typel idl) { Обработка исключений типа typel } catch(type2 id2) { Обработка исключений типа typeZ } catch(type3 ld2) { И т. д. } catch(typeN idN) Обработка исключений типа typeN Здесь продолжается нормальное выполнение программы... По своему синтаксису секции catch напоминают функции, вызываемые с одним аргументом. Идентификатор (idl, id2 и т. д.) может использоваться внутри обработчика по аналогии с аргументом функции, но если он не нужен - не используйте его. Тип исключения обычно дает достаточно информации для его обработки. Обработчики должны находиться сразу же после блока try. Если в программе запускается исключение, механизм обработки исключений начинает искать первый обработчик с аргументом, соответствующим типу исключения. Управление передается в найденную секцию catch, и исключение считается обработанным (то есть дальнейший поиск обработчиков прекращается). .Выполняется только нужная секция catch, а выполнение программы продолжается, начиная с позиции, следующей за последним обработчиком для данного блока try. Обратите внимание: в блоке try один тип исключения может генерироваться разными вызовами функций, но обработчик нужен только один. Для демонстрации работы конструкции try/catch в следующей версии файла Nonlocal.cpp вызов setjmp() заменен блоком try, а вызов longjmpO ~ командой throw: : C0bNonlocal2.cpp Демонстрация обработки исключений #include <iostream> using namespace std: class Rainbow { public: RainbowO { cout RainbowO endl: } -RainbowO { cout -RainbowO endl: } }: void ozO { Rainbow rb: for(int i = 0: i < 3: i++) cout theres no place like home\n : throw 47: int mainO { try { cout tornado, witch, munchkins...\n : ozO: catch (int) { cout Auntie Em! I had the strangest dream... В языке BASIC давно поддерживается ограниченная модель обработки исключений с продолжением программы (команда ON ERROR). При выполнении команды throw в функции oz() начинается перебор секций catch до тех пор, пока не будет обнаружена секция catch с параметром типа int. Тело этой секции catch продолжает выполнение программы. Важнейшее отличие этой версии от версии из файла Nonlocal.cpp состоит в том, что при выходе из функции oz() по команде throw вызывается деструктор объекта гЬ. Завершение и продолжение В теории обработки исключений существуют две основных модели: обработка с завершением программы и обработка с продолжением программы. В модели с завершением программы (поддерживаемой в С++) предполагается, что ошибка настолько серьезна, что автоматически продолжить программу с точки возникновения исключения нельзя. Другими словами, при запуске ис101ючения предполагается, что исправить ситуацию уже невозможно, и возвращаться нежелательно. Альтернативная модель обработки ошибок впервые появилась в языке PL/I в 1960-х годах Семантика этой модели предполагает, что обработчик исключения каким-то образом исправит ситуацию, после чего сбойный фрагмент кода будет автоматически выполнен заново; причем считается, что вторая попытка может оказаться успешной. Если вы захотите организовать подобную модель поведения в С++, вам придется явно передать управление к точке возникновения ошибки (обычно посредством вызова функции). Нередко блок try помещается в цикл while и выполняется до тех пор, пока результат не окажется удовлетворительным. История показывает, что программисты, которые работали в операционных системах с поддержкой модели с продолжением, в конечном счете переходили на имитацию модели с завершением. Продолжение программы на первый взгляд выглядит привлекательно, но на практике оно не столь полезно. Возможно, одной из причин является удаленность обработчика от точки, в которой возникло исключение. Просто уйти в удаленный обработчик несложно, тогда как переход в него с последующим возвратом может вызвать концептуальные трудности в больших системах, в которых исключения могут генерироваться во множестве мест. Поиск подходящего обработчика Когда в программе генерируется исключение, система обработки исключений начинает просматривать ближайшие обработчики в порядке их следования в исходном коде. Если она обнаруживает совпадение, исключение считается обработанным, и поиск на этом прекращается. Поиск подходящего обработчика не требует идеального соответствия между исключением и его обработчиком. Объект (или ссылка на объект) исключения производного класса считается подходящим для обработчика, работающего с базовым классом. (Однако если обработчик предназначен для объекта, а не для ссылки. endl: Более того, в обработчиках исключений практически всегда следует задавать объекты исключений по константной ссылке (модификация исключения с повторным запуском применяется редко). Тем не менее, мы не настаиваем на этом. объект исключения усекается до базового типа при передаче обработчику. Усечение безвредно, но оно приводит к потере всей информации, специфической для производного типа.) По этой причине, а также чтобы предотвратить создание лишней копии объекта исключения, всегда лучше перехватывать исключения по ссылке, а не по значению. При запуске указателя обработчик ишется по стандартным правилам преобразования указателей. Тем не менее, в процессе поиска автоматические преобразования одного типа ис101ючения к другому типу не выполняются. Пример: : C01:Autoexcp.cpp Отсутствие преобразований при поиске обработчика #include <iostream> using namespace std: class Exceptl {}: class Except2 { public: Except2(const Exceptl&) {} void fO { throw ExceptlO: } int mainO { try { fO: } catch (Except2&) { cout inside catch(Except2) endl: } catch (Exceptl&) { cout inside catch(Exceptl) endl: } /:- Хотя на первый взгляд может показаться, что первый обработчик может быть выбран в результате преобразования объекта Exceptl в ExceptZ с использованием преобразующего конструктора, при обработке исключений система не выполняет такие преобразования, и в итоге будет выбран обработчик Exceptl. Следующий пример показывает, как обработчик исключений базового класса перехватывает исключение производного класса: : C01:Basexcpt.cpp Иерархии исключений #incl ude <iostream> using namespace std: class X { public: class Trouble {}: class Small : public Trouble {}: class Big : public Trouble {}: void fO { throw BigO: } int mainO { X x:
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |