ЛИСТИНГ 28.1. Использование блоков try и catch для обеспечения
устойчивости к исключениям при резервировании памяти____________________________________
#include
using namespace std;
2 :
int main()
{
cout « "Enter number of integers you wish to reserve: ";
try
{
int Input = 0;
cin » Input;
1 0 :
// запрос области в памяти и ее последующее освобождение
int* pReservedlnts = new int [Input];
delete[] pReservedlnts;
}
catch (...)
{
17:- cout « "Exception encountered. Got to end, sorry!" << endl;
}
return 0;
20: }
20 3ak. 3626
ЗАНЯТИЕ 28. Обработка исключений
Результат
Enter number of integers you wish to reserve: -1 Exception encountered. Got to end, sorry!
Анализ
Для этого примера я указал количество резервируемых чисел -1 . Это абсурд, но поль зователи иногда делают абсурдные вещи. В отсутствие обработчика исключений работа программы закончилась бы некрасиво. Но благодаря обработчику исключения, как видите, вывод отображает осмысленное сообщение: G ot to e n d , s o r r y ! (Это конец, извините!).
ПРИМЕЧАНИЕ Если вы запускаете программу в среде разработки Visual Studio, то можете уви деть сообщение режима отладки, представленное на рис. 28.1.
И С . 28.1. Утверждение в связи с недопу стимым размером резервируемой памяти
Чтобы позволить сработать обработчику исключения, щелкните на кнопке Ignore (Игнорировать). Это сообщение режима отладки, но обработка исключений по зволяет вашей программе корректно закончить работу даже в режиме релиза.
Листинг 28.1 демонстрирует применение блоков c a tc h и tr y . Блок c a tc h () получает
параметры, как обычная функция, а означает, что блок c a tc h принимает исключе ния всех типов. Но в данном случае мы могли бы захотеть принимать исключения только типа s t d : :b a d _ a ll o c , поскольку именно они передаются при неудаче оператора new. Обработка исключений определенного типа позволяет рассматривать проблемы конкрет ного типа, в частности, например, отображать пользователю сообщение о том, что именно пошло не так.
Обработка исключения конкретного типа
Исключение в листинге 28.1 передавалось из стандартной библиотеки C++. Тип таких исключений известен, и их самостоятельная обработка проще, поскольку вы уже точно знаете причину исключения, можете лучше организовать очистку или, по крайней мере, отобразить пользователю конкретное сообщение, как в листинге 28.2.
Реализация устойчивости к исключениям при помощи блоков try и catch
|
611
|
Л И С Т И Н Г 2 8 .2 . Обработка исключения типа s t d : :bad
|
a llo c ______________________
|
|
0:
|
# in clu d e
|
|
|
|
|
1:
|
#include< exception>
|
/ / включите для обработки
|
исключения b ad _ a llo c
|
|
2:
|
u sin g
|
namespace s td ;
|
|
|
|
3:
|
|
|
|
|
|
|
4
|
: in t
|
main ()
|
|
|
|
|
5:
|
{
|
|
|
|
|
|
6:
|
cout « "E nter
|
number of in te g e rs you
|
wish
|
to re s e rv e : " ;
|
|
tr y
8 :{
9:
|
in t
|
In p u t = 0;
|
|
|
|
10:
|
c in
|
» In p u t;
|
|
|
|
1 1 :
|
|
|
|
|
|
12:
|
/ /
|
запрос области
|
в
|
памяти и
|
ее последующее освобождение
|
13:
|
in t*
|
p R eserv ed ln ts
|
=
|
new in t
|
[In p u t];
|
14:
|
d e l e t e [] p R e serv e d ln ts;
|
|
}
16: ca tc h (std ::b a d _ allo c& exp)
{
18:
|
cout
|
«
|
"E xception en co u n tered :
|
" « ex p .w h a t() « en d l;
|
19:
|
cout
|
«
|
"Got to end, s o rry !" «
|
en d l;
|
2 0 :
|
}
|
|
|
|
ca tc h ( . . . )
{
23: cout « "E xception en co u n tered . Got to end, s o rry !" « en d l;
}
Результат
Enter number of in te g e rs you wish to reserv e: -1
Exception encountered: bad a llo c a tio n
Got to end, sorry!
Анализ
Сравните вывод листинга 28.2 с выводом листинга 28.1. Как можно заметить, теперь вы в состоянии указать причину внезапного окончания работы приложения точней, а именно “bad allocation” (ошибка резервирования). Это связано с тем, что теперь есть до полнительный блок c a tc h (да, два блока c a tc h ), который обрабатывает исключения кон кретного типа c a tc h (b a d _ a llo c & ), как показано в строках 16-20.
Вы можете вставить столько блоков c a tc h (), сколько вам нужно, располагая их один за другим в зависимости от типа ожидаемых и вероятных исключений.
Блок c a tc h ( . . . ) , представленный в листинге 28.2, обрабатывает исключе ния всех типов, которые не были обработаны явно другими блоками catch .
612 ЗАНЯТИЕ 28. Обработка исключений
Передача исключения конкретного типа с использованием оператора throw
Когда вы обрабатывали исключение s t d : : b a d _ a l l o c в листинге 28.2, речь факти чески шла об объекте класса s t d : : b a d _ a ll o c , который передал оператор new. Но вы вполне можете самостоятельно передать исключение по собственному выбору. Для этого необходимо ключевое слово th ro w :
void DoSomething()
{
if(something_unwanted)
throw Value;
Давайте изучим применение оператора th ro w на примере собственного типа исключе ния, передаваемого при попытке деления на нуль, как представлено в листинге 28.3.
Л И СТИ Н Г 2 8 .3 . Передача специального исключения при попытке деления на нуль
#include
using namespace std;
double Divide(double Dividend, double Divisor)
{
if(Divisor == 0)
throw "Dividing by 0 is a crime";
7
return (Dividend / Divisor);
}
10
int main()
{
cout << "Enter dividend: ";
double Dividend = 0;
cin » Dividend;
cout << "Enter divisor: ";
double Divisor = 0;
cin » Divisor;
19
try
cout « "Result of division is: "
Divide(Dividend, Divisor);
}
catch(char* exp)
{
cout « "Exception: " « exp « endl;
cout « "Sorry, can't continue!" « endl;
}
29
return 0;
}
Как действует обработка исключений
|
613
|
Результат
Enter dividend: 2011
Enter divisor: 0
Exception: Dividing by 0 is a crime
Sorry, can't continue!
Анализ
Код не только демонстрирует возможность обработки исключения типа c h a r* , как показано в строке 24, но также и то, что возможна обработка исключения, переданного в функции D iv id e () в строке 6. Обратите также внимание на то, что в блок t r y {} за ключена не вся функция m ain (), а только та ее часть, где ожидается передача исключе ния. Это хорошая общепринятая практика, поскольку обработка исключений также может уменьшать производительность вашего кода.
Как действует обработка исключений
функции D iv id e () листинга 28.3 передавалось исключение типа c h a r* , которое об рабатывалось обработчиком c a tc h ( c h a r * ) в вызывающей функции m ain ().
Когда исключение передается с использованием оператора th ro w , компилятор встав ляет динамический поиск соответствующ его блока c a tc h , способного обработать это исключение. Логика обработки исключений подразумевает поиск передавшей исключе
ние строки сначала в пределах блока t r y . Если это так, то начинается поиск библиотеки c a tc h , который способен обработать исключение этого типа. Если оператор th ro w на ходится вне блока t r y или если нет блока c a tc h (), соответствующего типу исключения, логика обработки ищет то же самое в вызывающей функции. Так, логика обработки ис ключений двигается по стеку вызовов вверх, перебирая одну вызывающую функцию за другой, отыскивая подходящий блок c a tc h , способный обработать исключение данного типа. На каждом этапе прокрутки стека локальные переменные текущей функции уни чтожаются в порядке, обратном их созданию (листинг 28.4).
И СТИ Н Г 2 8 .4 . Порядок уничтожения локальных объектов в случае исключения_____________
#include
using namespace std;
:
struct StructA
{
Do'stlaringiz bilan baham: |