C++ Программирование в среде С++ Builder 5

Исключения и стек


Когда выбрасывается исключение, управление передается некоторому обработчику; он должен принадлежать функции, еще находящейся на стеке вызовов программы (см. в главе 5 об окне стека вызовов). Но эта функция не обязательно будет текущей функцией (выбросившей исключение). Например, пробный блок и обработчики находятся в одной функции, а исключение выбрасывается некоторой функцией, вызываемой из пробного ; блока; между ними может тянуться целая цепочка вложенных вызовов.

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

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

Приведем небольшую иллюстрацию. Ниже показана программа, состоящая из main () и двух функций FuncA () и FuncB () . Главная функция создает объект класса S и передает его FuncA (), которая его модифицирует и передает в FuncB (). Затем управление возвращается к main () .

Листинг 12.2. Работа стека при вызовах функций

///////////////////////////////////////////////////

// Stack.срp: Работа стека.

//

#include <iostream.h>

#pragma hdrstop

#include <condefs.h>



struct S // Простой класс. {

int s;

S(int ss): s(ss) // Конструктор (преобразования из int).

{

cout << "Constructor for "<< s << endl;

} S (const S& src) // Конструктор копии.

{

s = src.s;

cout << "Copy constructor for " << s << endl;

}

~S() // Деструктор.

{

cout << "Destructor of " << s << endl;


} };

void FuncB(S obj)

{

cout << "In FuncB: got << obj.s endl;

cout << "Exiting FuncB..." << endl;

}

void FuncA(S obj)

{

cout << "In FuncA: got"<< obj.s << endl;

obj.s = 22; // Модифицирует полученную копию объекта и...

FuncB(obj); // ...передает ее FuncB().

cout << "Exiting FuncA..." << end1;

}

int main() {

S mainObj = 11; // Локальный объект.

cout << "In main..." << endl; FuncA(mainObj);

cout << "Exiting main..." << endl;

return 0;

}

Программа выводит следующие сообщения:

Constructor for 11

In main...



Copy constructor for 11



In FuncA: got 11



Copy constructor for 22



In FuncB: got 22

Exiting FuncB...



Destructor of 22



Exiting FuncA...



Destructor of 22



Exiting main...

Destructor of 11

Здесь видно, как создается копия объекта при передачи параметра (по значению) и как она удаляется при возврате из функции.

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

Можно слегка модифицировать предыдущий пример, организовав пробный блок в main() и заставив FuncB() выбрасывать исключение в виде строки:



void FuncB(S obj)

{

cout << "In FuncB: got " << obj.s << endl;

cout << "Throwing exception..." << endl;

throw "Exception!";

cout << "Exiting FuncB..." << endl;

}

int main() {

S mainObj = 11; // Локальный объект.

cout << "In main..." << endl;

try {

FuncA(mainObj);

} catch(char* str) {

cout << "Gaught in main: " << str << end1;

} cout << "Exiting main..." << endl;

return 0;

}

Теперь программа выводит:

Constructor for 11

In main...



Copy constructor for 11



In FuncA: got 11

Copy constructor for 22

In FuncB: got 22

Throwing exception...



Destructor of 22

Destructor of 22



Caught in main: Exception!

Exiting main...

Destructor of 11

Временные копии объекта уничтожаются по-прежнему, хотя возврата из функции в обычном смысле слова не происходит.


Содержание раздела