Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Обработка исключительных ситуаций



Обработка исключительных ситуаций

На этом занятии мы представляем управление исключениями (исключительными ситуациями). Термин «исключение» подразумевает, что проблемная ситуация возникает нечасто — если «как правило» оператор исполняется корректно, то «исключением из правила» является возникновение ошибки. Управление исключениями дает программистам возможность создавать приложения, способные разрешать (или обрабатывать) исключительные ситуации. Во многих случаях обработка исключения позволяет программе продолжать выполнение, как будто никакой проблемы не возникало. Более серьезная проблема может не дать программе продолжаться нормально; в этом случае программа должна уведомить пользователя о проблеме и затем завершиться контролируемым образом.

 

Обзор управления исключениями

 

В программах часто используется проверка некоторых условий для определения дальнейших действий. Например, рассмотрим следующий псевдокод:

 

Выполнить задачу

Если предыдущая задача выполнилась некорректно

Выполнить обработку ошибок

Выполнить следующую задачу

Если предыдущая задача выполнилась некорректно

Выполнить обработку ошибок

 

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

Обработка исключений позволяет программисту вынести код обработки ошибок из «генеральной линии» выполнения программы. Это улучшает ясность программы и упрощает внесение в нее изменений. Программист может выбрать, какие исключения нужно обрабатывать — все виды исключений, исключения определенного типа или группу исключений родственных типов (например, типы исключений, входящих в иерархию наследования). Такая гибкость уменьшает вероятность того, что обработка каких-то ошибок не будет предусмотрена, и, таким образом, делает программу более устойчивой. В языках программирования, не поддерживающих обработку исключений, программисты часто откладывают написание процедур обработки ошибок или вообще забывают их написать. Получающиеся в результате программы менее устойчивы. C++ позволяет программисту задуматься над обработкой исключений уже при формировании концепции проекта.


 


Пример: обработка попытки деления на ноль

Давайте разберем простой пример управления исключениями Пример 1. Целью примера является предотвращение распространенной арифметической ошибки — деления на ноль. В C++ деление на ноль в целой арифметике обычно приводит к преждевременному завершению программы. В арифметике с плавающей точкой деление на ноль допускается; его результатом является положительная или отрицательная бесконечность, отображаемая как INF или —INF. В данном примере мы определяем функцию с именем quotient, которая принимает два введенных пользователем целых числа и делит свой первый целый параметр на второй. Перед выполнением деления функция приводит значение первого параметра к типу double. После этого значение второго целого параметра для вычисления возводится до double. Так что функция quotient по существу производит деление двух значений типа double и возвращает double. Хотя в арифметике с плавающей точкой деление на ноль допускается, в целях данного примера мы рассматриваем любую попытку деления на ноль как ошибку. Функция quotient перед тем, как перейти к делению, проверяет второй параметр, чтобы убедиться, что он ненулевой. Если второй параметр — ноль, функция посредством исключения уведомляет вызывающего о возникшей проблеме. Вызывающий (в данном случае main) может затем обработать это исключения и дает пользователю возможность ввести два новых значения, после чего снова вызывает quotient. Таким образом программа может продолжить исполнение, даже если вводится неправильное значение, т.е. она делается более устойчивой.

 

Заключение кода в try-блок

 

Программа начинается предложением пользователю ввести два целых числа. исла вводятся в условии цикла while (строка 32). После того как пользователь введет начения, представляющие делимое и делитель, управление переходит в тело цикла (строки 33-0). Строка 38 передает эти значения функции quotient (строки 13-21), которая либо делит их и возвращает результат, либо выбрасывает исключение (т.е. указывает, что произошла ошибка) при попытке деления на ноль. Управление исключениями приспособлено к ситуациям, когда функция, обнаружившая ошибку, не может обработать последнюю.

Для управления исключениями в C++ предусмотрены try-блоки. Такой блок состоит из ключевого слова try, за которым следуют фигурные скобки ({ и }), определяющие блок кода, где могут возникать исключения. В try-блок заключаются операторы, которые могли бы вызывать исключения, а также операторы, которые должны быть пропущены в случае, если исключение возникает.

Обратите внимание, что в try-блоке (строки 36-40) заключены вызов функции quotient и оператор, который выводит результат деления. В этом примере, поскольку вызов функции quotient (строка 38) может выбросить исключение, мы заключаем этот вызов в try-блок. Включение в try-блок оператора вывода (строка 39) гарантирует, что вывод будет производиться только в случае, когда quotient возвращает результат.

 

Перебрасывание исключений

Возможны случаи, когда обработчик, перехватив возникшее исключение, может решить, что он либо не может обработать это исключение, либо может обработать его только частично. В таких случаях обработчик исключения может передать обработку исключения (возможно, частично) другому обработчику. Это достигается путем перебрасывания исключения исполнением оператора throw;

Вне зависимости от того, способен ли обработчик обслужить исключение (хотя бы частично), он может перебросить его для дальнейшей обработки во внешнем коде. Следующий охватывающий try-блок детектирует переброшенное исключение, которое попытается обслужить обработчик, ассоциированный с этим try-блоком.

Спецификации исключений

Необязательная спецификация исключений (или список throw) перечисляет исключения, которые могут выбрасываться функцией. Рассмотрим, например, следующее объявление функции:

 

Разматывание стека

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

вызывается функция terminate для завершения программы. Программа в Пример 5 демонстрирует разматывание стека.

 

Блок try в main (строки 37-41) вызывает functionl (строки 27-31). Затем functionl вызывает function2 (строки 20-24), которая в свою очередь вызывает function3 (строки 11-17). Строка 16 функции function3 выбрасывает объект runtime__error. Однако поскольку оператор throw в строке 16 не охвачен никаким try-блоком, происходит разматывание стека: выполнение function3 завершается в строке 16, и управление возвращается оператору в function2, который вызвал function3 (т.е. строке 23). Поскольку строка 23 не охвачена никаким try -блоком, снова происходит разматывание стека — function2 завершается в строке 23 и возвращает управление оператору в functionl, который вызвал function2 (т.е. строке 30). Строка 30 также не охвачена try-блоком, и стек разматывается еще раз — functionl завершается в строке 30 и возвращает управление оператору в main, вызвавшему functionl (т.е. строке 40). Этот оператор охвачен try -блоком в строках 37-41, поэтому первый подходящий catch-обработчик после этого try -блока (строки 42-46) перехватывает и обрабатывает данное исключение. В строке 44 используется функция what, чтобы вывести сообщение об ошибке. Как вы помните, это виртуальная функция класса exception, которую можно переопределить в производном классе, чтобы выводилось соответствующее сообщение.

 

Обработка отказов new с использованием функции set_new_handler

Существует дополнительное средство, которое можно применить для реализации обработки отказов new. Функция set_new_handler (с прототипом в заголовочном файле < new> ) принимает в качестве аргумента указатель на функцию, которая не принимает аргументов и возвращает void. Этот указатель регистрируется как функция, которая должна вызываться при отказах new. Тем самым программисту предоставляется стандартный метод обработки всех отказов new вне зависимости от того, в каком месте программы возникла ошибка. После того как обработчик new зарегистрирован в программе вызовом set_new_handler, операция new при отказах не будет выбрасывать 

исключений bad_alloc; вместо этого она будет пересылать ошибку зарегистрированному обработчику.

Если new удалось выделить память, она возвращает указатель на нее. Если память выделить не удается и никакой функции обработчика new с помощью set__new_handler зарегистрировано не было, операция new выбрасывает исключение bad_alloc. Если память выделить не удается и была зарегистрирована функция обработчика new, то вызывается эта функция. Стандарт C++ определяет, что функция обработчика new должна выполнить одно из следующих действий:

 

1. Увеличить объем доступной памяти путем освобождения других областей динамической памяти (либо попросить пользователя закрыть другие приложения) и возвратиться к операции new, чтобы возобновить попытки выделения памяти.

2. Выбросить исключение типа bad_alloc.

3. Вызвать функцию abort или exit (обе из заголовочного файла < cstdlib> ) для завершения программы.

 

Программа в Примере 6 демонстрирует set_new_handler. Функция customNewHandler (строки 14-18) печатает сообщение об ошибке (строка 16), а затем завершает программу вызовом abort (строка 17). Вывод показывает, что программа выполнила всего две итерации цикла, после чего new потерпела неудачу и активировала функцию customNewHandler. У вас вывод программы может отличаться от нашего в зависимости от объема физической памяти, дискового пространства, доступного для виртуальной памяти на вашей системе, и используемого компилятора.

Обработка исключительных ситуаций

На этом занятии мы представляем управление исключениями (исключительными ситуациями). Термин «исключение» подразумевает, что проблемная ситуация возникает нечасто — если «как правило» оператор исполняется корректно, то «исключением из правила» является возникновение ошибки. Управление исключениями дает программистам возможность создавать приложения, способные разрешать (или обрабатывать) исключительные ситуации. Во многих случаях обработка исключения позволяет программе продолжать выполнение, как будто никакой проблемы не возникало. Более серьезная проблема может не дать программе продолжаться нормально; в этом случае программа должна уведомить пользователя о проблеме и затем завершиться контролируемым образом.

 


Поделиться:



Последнее изменение этой страницы: 2019-06-08; Просмотров: 160; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.018 с.)
Главная | Случайная страница | Обратная связь