Когда с помощью throw генерируется исключение, функции исполнительной библиотеки C++ выполняют следующие действия:
1) создают копию параметра throw в виде статического объекта, который существует
до тех пор, пока исключение не будет обработано;
2) в поисках подходящего обработчика раскручивают стек, вызывая деструкторы
локальных объектов, выходящих из области действия;
3) передают объект и управление обработчику, имеющему параметр, совместимый
по типу с этим объектом.
При раскручивании стека все обработчики на каждом уровне просматриваются
последовательно, от внутреннего блока к внешнему, пока не будет найден подходящий
обработчик.
Обработчик считается найденным, если тип объекта, указанного после throw:
• тот же, что и указанный в параметре catch (параметр может быть записан в форме Т, const Т, Т& или const Т&. где Т— тип исключения);
• является производным от указанного в параметре catch (если наследование производилось с ключом доступа public);
• является указателем, который может быть преобразован по стандартным правилам
|
|
преобразования указателей к типу указателя в параметре catch.
Из вышеизложенного следует, что обработчики производных классов следует размещать до обработчиков базовых, поскольку в противном случае им никогда не будет передано управление. Обработчик указателя типа void автоматически скрывает указатель любого другого типа, поэтому его также следует размещать после обработчиков указателей конкретного типа.
Рассмотрим пример:
// File TEST1.CPP
#include <iostream>
#include <fstream>
using namespace std;
class Hello
{
// Класс, информирующий о своем создании и уничтожении
public:
Hello(){cout << "Hello!" << endl;}
~Hello(){cout << "Bye!"<< endl;}
};
void f1()
{
setlocale(LC_ALL, "Russia");
ifstream ifs("\\INVALID\\FILE\\NAME");
if (ifs.fail())
{
cout << "Генерируем исключение"<< endl;
throw "Ошибка при открытии файла";
}
}
// Создаем локальный объект
// Вызываем функцию. генерирующую исключение
void f2()
{
Hello Н;
f1();
}
int main()
{
setlocale(LC_ALL, "russian");
try
{
cout << "Входим в try-блок"<< endl;
f2();
cout<< "Выходим из try-блока" << endl;
}
catch(int i)
{
cout << "Вызван обработчик int. исключение - " << i << endl;
return -1;
}
catch (const char * p)
{
cout<< "Вызван обработчик const char*, исключение - "
<< p << endl;
return -1;
}
catch(...)
{
cout << "Вызван обработчик всех исключений" << endl;
return -1;
}
return 0; // Все обошлось благополучно
}
Результаты выполнения программы: