Хелпикс

Главная

Контакты

Случайная статья





Основы обработки исключений



Основы обработки исключений

Обработка исключений в С++ использует три ключевых слова: try, catch и throw.

Блок try {...} позволяет включить один или несколько операторов, которые могут создавать исключение.

Выражение throw используется только в программных исключениях и означает, что исключительное условие произошло в блоке try. В качестве операнда выражения throw можно использовать объект любого типа. Обычно этот объект используется для передачи информации об ошибке.

Для обработки исключений, которые могут быть созданы, необходимо реализовать один или несколько блоков catch сразу после блока try. Каждый блок catch указывает тип исключения, которое он может обрабатывать.

Сразу за блоком try находится защищенный раздел кода. Выражение throw вызывает исключение, т.е. создает его.

Блок кода после catch является обработчиком исключения. Он перехватывает исключение, вызываемое, если типы в выражениях throw и catch совместимы. Если оператор catch задает многоточие (...) вместо типа, блок catch обрабатывает все типы исключений.
Поскольку блоки catch обрабатываются в порядке программы для поиска подходящего типа, обработчик с многоточием должен быть последним обработчиком для соответствующего блока try. Как правило, блок catch(...) используется для ведения журнала ошибок и выполнения специальной очистки перед остановкой выполнения программы.

try { ... // защищенный раздел кода

throw параметр;

}

catch (параметр) { // обработка исключения }

catch (...) { // обработка остальных исключений }

 

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

Размеры блока try могут изменяться в больших пределах. Например, блок try может содержать несколько инструкций какой-либо функции, либо же, напротив, включать в себя весь код функ­ции main(), так что вся программа будет охвачена обработкой исключений.

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

Общая форма записи инструкции throw имеет вид:

throw исключение;

Инструкция throw должна выполняться либо внутри блока try, либо в функции, вызванной из блока try. В записанном выше выражении исключение обозначает сгенерированное значение.

Если генерируется исключение, для которого отсутствует подходящая инструкция catch, может произойти аварийное завершение программы. При генерации необработанного исключения
вызывается функция terminate(). По умолчанию terminate() вызывает функцию abort(), завершаю­щую выполнение программы. Однако можно задать свою собственную обработку, используя фун­кцию set_terminate(). Подробности можно найти в документации к компилятору.

Ниже представлен пример, иллюстрирующий способ обработки исключений в С++:

// пример обработки простого исключения
#include <iostream.h>
int main()
{
cout << "Start\n";
try { // начало блока try
cout << "Inside try block\n";
throw 100; // генерация ошибки
cout << "This will not execute";
}
catch (int i) { // перехват ошибки
cout << "Caught an exception -- value is: ";
cout << i << " \n";
}
cout << "End";
return 0;
}

Программа выведет на экран следующий текст:

Start
Inside try block
Caught an exception -- value is: 100
End

Рассмотрим внимательнее эту программу. Как можно видеть, блок try содержит три инструкции. За ним следует инструкция catch(int i), обрабатывающая исключения целого типа. В блоке try будут выполняться только две инструкции: первая и вторая — throw. Как только исключение было сгенерировано, управление передается инструкции catch, а блок try прекращает свое исполнение. Таким образом, catch не вызывается. Скорее можно сказать, что к ней переходит исполнение программы. Для этого автоматически осуществляется переустановка стека. Таким образом, инст­рукция после инструкции throw никогда не выполняется.

Обычно код в инструкции catch пытается исправить ошибку путем выполнения подходящих действий. Если ошибку удалось исправить, то выполнение продолжается с инструкции, непосред­ственно следующей за catch. Однако иногда не удается справиться с ошибкой, и блок catch завер­шает программу путем вызова функции exit() или функции abort().

Как отмечалось, тип исключения должен соответствовать указанному в инструкции типу. Напри­мер, в предыдущем примере если изменить тип инструкции catch на double, то исключение не будет перехвачено и произойдет аварийное завершение программы. Такое изменение показано ниже:

// данный пример не будет работать
#include <iostream.h>
int main()
{
cout << "Start\n";
try { // начало блока try
cout << "Inside try block\n";
throw 100; // генерация ошибки
cout << "This will not execute";
}
catch (double i) { // не будет работать для целочисленного исключения
cout << "Caught an exception -- value is: ";
cout << i << "\n";
}
cout << "End";
return 0;
}

Эта программа выдаст следующий результат, поскольку исключение целого типа не будет пере­хвачено инструкцией catch (double i):

Start
Inside try block
Abnormal program termination

Исключение может также быть сгенерировано из функции, вызванной изнутри блока try. В качестве примера рассмотрим следующую программу:

/* генерация исключения из функции, находящейся вне блока try
*/
#include <iostream.h>
void Xtest(int test)
{
cout << "Inside Xtest, test is: " << test << "\n";
if (test) throw test;
}
int main()
{
cout << "Start\n";
try { // начало блока try
cout << "Inside try block\n";
Xtest (0);
Xtest (1);
Xtest (2);
}
catch (int i) { // перехват ошибки
cout << "Caught an exception -- value is: ";
cout << i << "\n";
}
cout << "End";
return 0;
}

Эта программа выдаст следующий результат:

Start
Inside try block
Inside Xtest, test is: 0
Inside Xtest, test is: 1
Caught an exception -- value is: 1
End

Блок try может быть локализован в какой-то функции. В таком случае всякий раз при входе в функцию начинается обработка исключений. В качестве примера рассмотрим следующую про­грамму:
#include <iostream.h>
// try/catch могут находиться в функции вне main()
void Xhandler(int test)
{
try {
if (test) throw test;
}
catch(int i) {
cout << "Caught Exception #: " << i << '\n';
}
}
int main()
{
cout << "Start\n";
Xhandler(1);
Xhandler(2);
Xhandler(0);
Xhandler(3);
cout << "End";
return 0;
}

Эта программа выдаст на экран следующий текст:

Start
Caught Exception #: 1
Caught Exception #: 2
Caught Exception #: 3
End

Как видно, сгенерировано три исключения. После каждого исключения функция возвращает управ­ление в функцию main. При каждом новом вызове функции возвращается обработка исключений.

Важно понимать, что код, ассоциированный с инструкцией catch, будет исполняться только тогда, когда перехвачено исключение. В противном случае выполнение программы просто обойдет инструкцию catch.



  

© helpiks.su При использовании или копировании материалов прямая ссылка на сайт обязательна.