Г. Шилтд - Самоучитель C++ (PDF) (1114887), страница 51
Текст из файла (страница 51)
Это приводит к тому, что текущая исключительная ситуация передается внешней последовательности инструкций try/catch.Примеры1. В следующей программе иллюстрируется использование инструкции catch(...):// В этой программе перехватываются все типы исключительных ситуаций^include <iostream>using namespace std;void Xhandler(int test)try {// возбуждение исключительной ситуации типа intif(test==0) throw test;346Самоучитель C++// возбуждение исключительной ситуации типа charif(test==l) throw 'a';// возбуждение исключительной ситуации типа doubleif (test—2) throw 123.23;}catch (...) { // перехват исключительных ситуаций всех типовcout « "Перехвачена ошибка!\п";}int main ()cout « "начало\п";Xhandler(O);Xhandler(l);Xhandler(2);cout « "конец "return 0;На экран программа выводит следующее:началоПерехвачена ошибка !Перехвачена ошибка !Перехвачена ошибка !конецКак видите, во всех трех случаях возбуждения исключительной ситуации винструкции throw, она перехватывается с помощью единственной инструкции catch.2.
Очень удобно инструкцию catch(...) использовать в качестве последней вгруппе инструкций catch. В этом случае инструкция catch(...) по умолчаниюстановится инструкцией, которая "перехватывает все". Например, далее представлена слегка измененная версия предыдущей программы, где исключительные ситуации целого типа перехватываются явно, а все другие — с помощью инструкции catch(...):/* В этом примере инструкция catch (...) по умолчанию перехватываетвсе типы исключительных ситуаций*/^include <io5tream>using namespace std;void Xhandler(int test)Глава11.Шаблоныиобработкаисключительныхситуаций_347t су {// возбуждение исключительной ситуации типа intif(test=0) throw test;// возбуждение исключительной ситуации типа charif (test— 1} throw 'a';// возбуждение исключительной ситуации типа doubleif (test— 2) throw 123.23;}catch(int i) { // перехват исключительной ситуации типа intcout « "Перехвачен " « i « '\n';}catch (...) { // перехват исключительных ситуаций остальных типовcout « "Перехвачена ошибка ! \п" ;int main {){cout « "начало\п " ;Xhandler(O) ;Xhandler(l) ;Xhandler(2) ;cout « "конец";return 0;На экран программа выводит следующее:началоПерехвачен ОПерехвачена ошибка!Перехвачена ошибка!конецКак показано в этом примере, использование инструкции catch(...) такимобразом — это хороший способ перехватывать те исключительные ситуации,которые вы не хотите обрабатывать явно.
Кроме этого, путем перехвата всехисключительных ситуаций вы предотвращаете аварийное завершение программы из-за случайно необработанной исключительной ситуации.3. В следующей программе показано, как ограничить число типов исключительных ситуаций, которые возбуждаются функцией:/* Ограничение числа возбуждаемых функцией типов исключительныхситуаций*/ttinclude <iostreara>using namespace std;348___СамоучительC++II Этой функцией могут возбуждаться только// исключительные ситуации типов int, char и doublevoid Xhandler (int test) throw(int, char, double){// возбуждение исключительной ситуации типа intif (test—0) throw test;// возбуждение исключительной ситуации типа charif(test=l) throw r a r ;// возбуждение исключительной ситуации типа doubleifttest— 2) throw 123.23;int main ()(cout « "начало\п";try {Xhandler(O); // попробуйте также передать в// функцию Xhandler () значения 1 и 2catch (int i) {cout « "Перехват int\n";Jcatch (char c) jcout « "Перехват char\n";}catch (double d) {cout « "Перехват double\n" ;}cout « "конец" ;return 0;В этой программе функция Xhandler() может возбуждать только исключительные ситуации типа int, char и double.
При попытке возбудить исключительную ситуацию другого типа произойдет аварийное завершение программы. (То есть будет вызвана функция unexpected<>.) Чтобы убедиться в этом,удалите из списка допустимых исключительных ситуаций тип int и повторитезапуск программы.Важно понимать, что ограничить типы возбуждаемых исключительных ситуаций можно только после того, как функция вызвана из блока try- To естьвнутри функции блок try может возбудить любой тип исключительной ситуации, коль скоро она перехватывается внутри этой функции. Ограничениявступают в силу только тогда, когда исключительная ситуация не перехвачена функцией.Глава11.Шаблоныиобработкаисключительныхситуаций_3494. Следующее небольшое изменение в функции Xhandler() запрещает возбуждение любой исключительной ситуации:// Эта функция НЕ может вызывать никаких исключительных ситуацийvoid Xhandler (int test) throw ( )/*Следующие инструкции больше не работают.
Наоборот, попытка ихвыполнения ведет к ненормальному завершению программы*/// возбуждение исключительной ситуации типа intif (test==0) throw test;// возбуждение исключительной ситуации типа charif(test==l) throw 'a';// возбуждение исключительной ситуации типа doubleif(test=2J throw 123.23;Вы уже знаете, что можно повторно возбудить исключительную ситуацию.Смысл этого в том, чтобы предоставить возможность обработки исключительной ситуации нескольким процедурам. Например, предположим, что одна процедура обрабатывает один аспект исключительной ситуации, а вторая — другой. Повторно исключительная ситуация может быть возбужденатолько внутри блока catch (или любой функцией, которая вызывается изэтого блока).
Когда вы повторно возбуждаете исключительную ситуацию, онаперехватывается не той же инструкцией catch, а переходит к другой, внешней к данной инструкции. В следующей программе иллюстрируется повторное возбуждение исключительной ситуации: возбуждается исключительнаяситуация типа char *./* Пример повторного возбуждения исключительной ситуации одного итого же типа*/^include <iostream>using namespace std;void Xhandler (){try {// возбуждение исключительной ситуации типа char *throw "привет";j// перехват исключительной ситуации типа char *catch (char *) {cout « "Перехват char * внутри функции Xhandler () \n";/ / повторное возбуждение исключительной ситуации// типа char *, но теперь уже не в функции Xhandler ()throw;Самоучитель C++350intmain()cout « "началсЛп";try {XhandlerO ;}catch(char *) {cout « " Перехват char * внутри функции main()\n";}cout « "конец";return 0;На экран программа выводит следующее:началоПерехват char * внутри функции XhandlerOПерехват char * внутри функции main()конец\.
Перед тем как двинуться дальше, откомпилируйте и запустите все примерытекущего раздела. Убедитесь, что вы понимаете, почему каждая программавыводит на экран ту или иную информацию.2. Что неправильно в данном фрагменте?try{// ...throw 10;}catch (int *p) {3. Предложите способ исправления предыдущего фрагмента.4. Какая инструкция catch перехватывает все типы исключительных ситуаций?5. Далее представлен каркас функции dividcQdouble divide (double a, double b){// добавьте обработку ошибокreturn a/b;Глава 11.
Шаблоны и обработка исключительных ситуаций35?Эта функция возвращает результат деления а на Ь. Добавьте в функцию процедуру обработки исключительных ситуаций, а конкретно предусмотрите обработку ошибки деления на ноль. Покажите, что ваша процедура работает.11.5. Обработка•исключительных ситуации,возбуждаемых оператором newvВ главе 4 вы получили представление о том, что в соответствии с современной спецификацией оператора new, он возбуждает исключительную ситуацию при неудачной попытке выделения памяти. Поскольку в главе 4 об исключительных ситуациях мы еще не знали, описание того, как они обрабатываются было отложено. Теперь настало время подробно исследоватьситуацию неудачной попытки выделения памяти с помощью оператора new.В материале этого раздела атрибуты оператора new описаны так, как это определено в современном едином международном стандарте Standard C++.Как уже упоминалось в главе 4, с момента появления языка C++ точноеопределение действий, которые должны выполняться при неудачной попытке выделения памяти с помощью оператора new, менялось несколько раз.Сразу после разработки языка при неудачной попытке выделения памятиоператор new возвращал нуль, несколькими годами позднее — возбуждалисключительную ситуацию.
Кроме того, неоднократно менялось имя этойисключительной ситуации. В конце концов было решено, что неудачная попытка выделения памяти с помощью оператора new по умолчанию будетвозбуждать исключительную ситуацию, но по желанию в качестве опцииможно возвращать нулевой указатель. Таким образом, оператор new реализовывался по-разному в разное время разными производителями компиляторов. Хотя в будущем все компиляторы должны быть выполнены в точномсоответствии с требованиями стандарта Standard C++, сегодня это не так.Если представленные здесь примеры программ у вас не работают, проверьтепо документации вашего компилятора то, как именно в нем реализованоператор new.В соответствии со стандартом Standard C++, когда требование на выделениепамяти не может быть выполнено, оператор new возбуждает исключительную ситуацию bad_alloc.
При невозможности перехватить эту исключительную ситуацию программа завершается. Хотя для коротких программ такойалгоритм кажется вполне очевидным и понятным, в реальных приложенияхвы должны не только перехватить, но и каким-то разумным образом обработать эту исключительную ситуацию. Для доступа к указанной исключительной ситуации в программу необходимо включить заголовок <new>.352Самоучитель C++Изначально описанная выше исключительная ситуация называлась xalloc иво время написания данной книги это имя продолжало использоваться намногих компиляторах.
Тем не менее в дальнейшем оно, несомненно, будетвытеснено определенным в стандарте Standard C++ именем bad_alloc.Как уже упоминалось, в соответствии с требованиями стандарта StandardC++ при неудачной попытке выделения памяти допускается, чтобы оператор new возвращал нуль, а не возбуждал исключительную ситуацию. Такаяформа оператора new может оказаться полезной при компиляции устаревших программ на современном компиляторе, а также при замене функцийmalloc() операторами new.