Г. Шилтд - Самоучитель C++ (DJVU) (1114955), страница 52
Текст из файла (страница 52)
При попытке возбудить исключительную ситуацию другого типа произойдет аварийное завершение программы. (То есть будет вызвана функция ипехресМЙ().) Чтобы убедиться в этом, удалите из списка допустимых исключительных ситуаций тип )п( и повторите запуск программы. Важно понимать, что ограничить типы возбуждаемых исключительных ситуаций можно только после того, как функция вызвана из блока 1гу. То есть внутри функции блок 1гу может возбудить любой тип исключительной ситуации, коль скоро она перехватывается внутри этой функции. Ограничения вступают в силу только тогда, когда исключительная ситуация не перехвачена функцией. Глава 1 1. Шаблоны и обработка исключительных ситуаций 349 4.
Следующее небольшое изменение в функции Храп(Иег() запрещает возбуждение любой исключительной ситуации: О Эта функция НЕ может вызывать никаких исключительных ситуаций чоЫ Х).апс)1ег (1пс техт) г)згои ,') /*Следуюл(ие инструкции больше не работают. Наоборот, попытка их выполнения ведет к ненормальному завершению программы ж/ возбуждение исключительной ситуации тига гпг 1г (сеяс=-=О) г)тгои геяг; // возбуждение исключительной ситуации типа сиаг ьй(сеял==1) г)тгоы 'а'; возбуждение исключительной ситуации типа с(оп)з1е гг(сеяг=2т гЬгоы 123.23; 5. Вы уже знаете, что можно повторно возбудить исключительную ситуацию. Смысл этого в том, чтобы предоставить возможность обработки исключительной ситуации нескольким процедурам.
Например, предположим, что одна процедура обрабатывает один аспект исключительной ситуации, а вторая — другой. Повторно исключительная ситуация может быть возбуждена только внутри блока сатен (или любой функцией, которая вызывается из этого блока).
Когда вы повторно возбуждаете исключительную ситуацию, она перехватывается не той же инструкцией са1с)), а переходит к другой, внешней к данной инструкции. В следующей программе иллюстрируется повторное возбуждение исключительной ситуации: возбуждается исключительная ситуация типа сваг *. /* Пример повторного возбуждения исключительной ситуации одного и того же типа */ ()1пс1цде <фояегеазл> иягпд паюеярасе всЙ) чоз от х)тапс11ег () бгу возбуждевие исключительной ситуации типа сваг * б)тгоы "привет"; перехват исключительной ситуации ттпта с)заг * сакс)з (с)заг *) сонг с< "перехват с)тат * внутри функции х)запс)1ег () 1п"; / / повторное возбуждение исключительной сытуации типа с)заг *, но теперь уже не в функции х)загс)1ег () Г'пгои; Самоучитель С++ 1пт таз.п () ( сочс « "начало',и"; Ьту ( ХЬапс(1ет (); ) сассЬ(сЬат *) со С « " Перехват сЬат * внутри функции питп()~п"; сочв « "конец"; тесчтп 0; На экран программа выводит следующее: начало Перехват сЬат * внутри функции ХЬапс(1етО Перехват сЬат * внутри футпсции тватп() конец Перед тем как двинуться дальше, откомпилируйте и запустите все примеры текущего раздела.
Убедитесь, что вы понимаете, почему каждая программа выводит на экран ту или иную информацию. 2. Что неправильно в данном фрагменте? 1ту ( // ". 1Ь том 10; са(сЬ (1п( Р) ( /у 3. Предложите способ исправления предыдущего фрагмента. 4. Какая инструкция са1с(( перехватывает все типы исключительных ситуаций? 5. Далее представлен каркас функции ЙтЫе(), доцЫе с(ть Ие (бочЬ1е а, доцЫе Ь) // добавьте обработку ошибок песчкп а/Ь; Глава 11, Шаблоны и обработка исключительных ситуаций Э51 Эта функция возвращает результат деления а на Ь.
Добавьте в функцию процедуру обработки исключительных ситуаций, а конкретно предусмотрите обработку ошибки деления на ноль. Покажите, что ваша процедура работает. 11.5. Обработка исключительных ситуаций, возбуждаемых оператором печч В главе 4 вы получили представление о том, что в соответствии с современной спецификацией оператора пев, он возбуждает исключительную ситуацию при неудачной попытке выделения памяти. Поскольку в главе 4 об исключительных ситуациях мы еще не знали, описание того, как они обрабатываются было отложено. Теперь настало время подробно исследовать ситуацию неудачной попытки выделения памяти с помощью оператора пеп.
В материале этого раздела атрибуты оператора пев описаны так, как это определено в современном едином международном стандарте Яапдагд С++. Как уже упоминалось в главе 4, с момента появления языка С++ точное определение действий, которые должны выполняться при неудачной попытке выделения памяти с помощью оператора пеи, менялось несколько раз. Сразу после разработки языка при неудачной попытке выделения памяти оператор печ возвращал нуль, несколькими годами позднее — возбуждал исключительную ситуацию. Кроме того, неоднократно менялось имя этой исключительной ситуации. В конце концов было решено, что неудачная попытка выделения памяти с помощью оператора печт по умолчанию будет возбуждать исключительную ситуацию, но по желанию в качестве опции можно возвращать нулевой указатель. Таким образом, оператор пест реализовывался по-разному в разное время разными производителями компиляторов.
Хотя в будущем все компиляторы должны быть выполнены в точном соответствии с требованиями стандарта Вгапдагд С++, сегодня это не так. Если представленные здесь примеры программ у вас не работают, проверьте по документации вашего компилятора то, как именно в нем реализован оператор пеж. В соответствии со стандартом $1апдагд С++, когда требование на выделение памяти не может быть выполнено, оператор пев возбуждает исключительную ситуацию Ьпп пИос. При невозможности перехватить эту исключительную ситуацию программа завершается.
Хотя для коротких программ такой алгоритм кажется вполне очевидным и понятным, в реальных приложениях вы должны не только перехватить, но и каким-то разумным образом обработать эту исключительную ситуацию. Для доступа к указанной исключительной ситуации в программу необходимо включить заголовок <пев). 352 Само читель С+~ Изначально описанная выше исключительная ситуация называлась ханое и во время написания данной книги это имя продолжало использоваться на многих компиляторах. Тем не менее в дальнеишем оно, несомненно, будет вытеснено определенным в стандарте Б1апг(аМ С++ именем ьагг аиоо.
Как уже упоминалось, в соответствии с требованиями стандарта Мапатс( С++ при неудачной попытке выделения памяти допускается, чтобы оператор пеи возвращал нуль, а не возбуждал исключительную ситуацию. Такая форма оператора пеи может оказаться полезной при компиляции устаревших программ на современном компиляторе, а также при замене функций тпаПосО операторами пев. Ниже представлена именно эта форма оператора пев' укааааелв = пви(поьпгои) йип! Здесь указатель — это указатель на переменную типа тил. Форма оператора певуч с ключевым словом пойгов (без вызова исключительной ситуации) функционирует аналогично его прежней, изначальной версии. Поскольку в этом случае при неудачной попытке выделения памяти возвращается нуль, оператор пев может быть легко "встроен" в старые программы и вам не нужно заботиться о формировании процедуры обработки какой бы то ни было исключительной ситуации.
Тем не менее, в новых программах механизм исключительных ситуаций предоставляет вам гораздо более широкие возможности. 1. В представленном ниже примере с оператором пе1у использование блока 1гу/са1сЬ дает возможность проконтролировать неудачную попытку выделения памяти. (((пс1це(е <товсгеал» (Г! ПС1ПЙ <пея> ПБ1ПЯ пап!еарасе асе(1 !П( ~пагп ( ! 1пг *р; ггу ( р = пеи 1п1; // выделение памяти для целого сагой (Ьас( а11ОС ха) ( соцс « "Ошибка выделения памяти~в" 1 Глава 1 1. Шаблоны и обработка исключительных ситуаций 353 гоги гп 1; ГОГ(*р = О; ар < 10; (+р)++) сош « *р « бе1есе р1 // освобождение памяти гегш п О; В данном примере, если при вьщелении памяти случается ошибка, она перехватывается инструкцией сатс)1.
2. Поскольку в предыдущей программе при работе в нормальных условиях ошибка выделения памяти чрезвычайно маловероятна, в представленном ниже примере для демонстрации возможности возбуждения исключительной ситуации оператором пе1у Ошибка выделения памяти достигается принудительно. Процесс выделения памяти длится до тех пор, пока не произойдет ошибка. ()1пс1пбе <1авСтеат> ()ьпс1пбе <пеи> цвтпс пзюеврасе есб; тпс таад 0 боцЫе *Рг цикл будет продолжаться впдоть до исчерпания ресурса памяти с1о сгу ( р = пеи боиЬ1е(100000]; ) сагсЬ (Ьаб а11ос ха) ( сепг « "Ошибка выделения памятиХп" 1 гегпгп 1; ) сопГ « "Выделение памяти идет нормальноХп"; ) иМ.1е (р); гегигп О; 3, В следующей программе показано, как использовать альтернативную форму оператора пеи — оператор пеи'(пе1егет1().
Это переработанная версия предыдущей программы с принудительным возбуждением исключительной ситуации. // Демонстрация работы оператора пеи(погьгои) ()1пс1пбе <ьое~теап1> ()1пс1пбе <пеи> Самоучитель С++ цз!па патезрасе асс(; 10[ ва1п (1 доцЫе "р; цикл будет продолжаться вплоть до исчерпания ресурса паияти Йо ( р = пеи(повнлои[ с(опЬ1е 11000001[ 1Е(р1 сов[ « "Выделение памяти идет нормально1п"г е(зе соШ « "Ошибка выделения памятихп"[ 1 иЫ1е(р[; гегогп 0; Как показано в этой программе, при использовании оператора печ~ с ключевым словом по1Ьгои, после каждого запроса на выделение памяти следует проверять возвращаемое оператором значение указателя. 1. Объясните, в чем разница между функционированием операторов пеи и пе(т(по1Ьота), если при выделении памяти происходит ошибка. 2.