Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
В механизме исключений C++ элемент управления перемещается из оператора throw в первый оператор catch, который может обработать выданный тип. После достижения инструкции catch все автоматические переменные, которые находятся в области между операторами throw и catch, уничтожаются в процессе, который называется очисткой стека. При очистке стека выполнение продолжается следующим образом.
Элемент управления достигает инструкции по обычному последовательному
tryвыполнению. Выполняется защищенный раздел в блокеtry.Если исключение не возникает во время выполнения защищенного раздела, предложения, следовать за
catchблоком,tryне выполняются. Выполнение продолжается в инструкции после последнегоcatchпредложения, следующего за связаннымtryблоком.Если исключение создается во время выполнения защищенного раздела или в любой подпрограмме, вызываемой защищенным разделом напрямую или косвенно, создается объект исключения из объекта, созданного операндом
throw. (Это означает, что конструктор копирования может быть вовлечен.) На этом этапе компилятор ищетcatchпредложение в более высоком контексте выполнения, которое может обрабатывать исключение создаваемого типа илиcatchобработчика, который может обрабатывать любой тип исключения. Обработчикиcatchпроверяются в порядке их внешнего вида послеtryблока. Если соответствующий обработчик не найден, проверяется следующий динамически заключенныйtryблок. Этот процесс продолжается до тех пор, пока не будет рассмотрен самый внешний заключиющийtryблок.Если соответствующий обработчик по-прежнему не найден или исключение возникает во время процесса очистки до получения элемента управления обработчиком, вызывается предопределенная функция времени выполнения
terminate. Если исключение возникает после создания исключения, но до начала процесса очистки, вызывается функцияterminate.Если соответствующий обработчик найден, и он перехватывается по значению, его формальный
catchпараметр инициализируется путем копирования объекта исключения. Если обработчик выполняет перехват по ссылке, параметр инициализируется для ссылки на объект исключения. После инициализации формального параметра начинается процесс очистки стека. Это включает в себя уничтожение всех автоматических объектов, которые были полностью созданы , но еще не деструированы, между началомtryблока, связанного сcatchобработчиком и сайтом создания исключения. Удаление происходит в порядке, обратном созданию. Обработчикcatchвыполняется, и программа возобновляет выполнение после последнего обработчика, то есть при первой инструкции или конструкции, которая не является обработчикомcatch. Элемент управления может вводитьcatchобработчик только через исключение, вызываемое исключение, никогда не с помощьюgotoинструкции илиcaseметки в инструкцииswitch.
Пример очистки стека
В следующем примере показано, как очистить стек при создании исключения. Выполнение потока переходит от оператора throw в C к оператору catch в main, и при этом удаляются все функции. Обратите внимание, что порядок создания и удаления объектов Dummy соответствует порядку их выхода из области видимости. Также обратите внимание, что завершается выполнение только функции main, содержащей оператор catch. Функция A никогда не возвращается после вызова B(), и B никогда не возвращается после вызова C(). Обратите внимание, что если раскомментировать определение указателя Dummy и соответствующую инструкцию DELETE, а затем запустить программу, указатель не удаляется. Это показывает, что может произойти, если функции не предоставляют гарантию исключения. Дополнительные сведения см. в разделе "Практическое руководство . Проектирование исключений". Если закомментировать оператор catch, можно наблюдать за тем, что происходит при завершении выполнения программы в результате необработанного исключения.
#include <string>
#include <iostream>
using namespace std;
class MyException{};
class Dummy
{
public:
Dummy(string s) : MyName(s) { PrintMsg("Created Dummy:"); }
Dummy(const Dummy& other) : MyName(other.MyName){ PrintMsg("Copy created Dummy:"); }
~Dummy(){ PrintMsg("Destroyed Dummy:"); }
void PrintMsg(string s) { cout << s << MyName << endl; }
string MyName;
int level;
};
void C(Dummy d, int i)
{
cout << "Entering FunctionC" << endl;
d.MyName = " C";
throw MyException();
cout << "Exiting FunctionC" << endl;
}
void B(Dummy d, int i)
{
cout << "Entering FunctionB" << endl;
d.MyName = "B";
C(d, i + 1);
cout << "Exiting FunctionB" << endl;
}
void A(Dummy d, int i)
{
cout << "Entering FunctionA" << endl;
d.MyName = " A" ;
// Dummy* pd = new Dummy("new Dummy"); //Not exception safe!!!
B(d, i + 1);
// delete pd;
cout << "Exiting FunctionA" << endl;
}
int main()
{
cout << "Entering main" << endl;
try
{
Dummy d(" M");
A(d,1);
}
catch (MyException& e)
{
cout << "Caught an exception of type: " << typeid(e).name() << endl;
}
cout << "Exiting main." << endl;
char c;
cin >> c;
}
/* Output:
Entering main
Created Dummy: M
Copy created Dummy: M
Entering FunctionA
Copy created Dummy: A
Entering FunctionB
Copy created Dummy: B
Entering FunctionC
Destroyed Dummy: C
Destroyed Dummy: B
Destroyed Dummy: A
Destroyed Dummy: M
Caught an exception of type: class MyException
Exiting main.
*/