Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Курс лекцій.doc
Скачиваний:
17
Добавлен:
03.11.2018
Размер:
1.12 Mб
Скачать

13.2.5 Робота з специфікаціями виключень

Можна задавати список виключень, які функція може викидати, за допомогою специфікації виключень, що приєднується до заголовка функції. Специфікація має наступний формат:

throw( тип, тип, ...)

Специфікація виключень без типа вказує, що функція не повинна викидати ніяких виключень. Функції без специфікацій навпаки можуть викидати будь-які виключення. Приклад:

struct xClass{

int i;}

void funcA(void) throw(int)

{ }

void funcB(void) throw(long,xClass*)

{ }

void funcC(void) throw()

{ }

13.2.6 Робота з непередбаченими виключеннями

Спеціфікації виключень, власне кажучи, ні до чого не зобов’язують. Тобто функція може прямо чи викинути виключення, яке вона обіцяла не використовувати. При компіляції ніякої помилки не буде:

void func(void) throw(int)

{

throw ”Ой!”;

}

Порушення списку допустимих виключень виявляється тільки під час виконання. Непередбачене виключення приводить до виклику функції unexpected(). По замовчуванню unexpected() просто викликає функцію terminate(). Однак за допомогою функції set_unexpected() можна встановити свою власну процедуру, яка буде викликатись в момент викиду неспецифікованого виключення. Функція set_unexpected() визначена в файлі EXCEPT.H:

typedef void(_RTLENTRY *unexpected function)();

// . . .

unexpected_function _RTLENTRY

set_unexpected(unexpected_function);

Функція повертає адресу попередньої процедури для непередбачених виключень. Ваша процедура не може повертати управління чи викидати виключення.

13.2.7 Робота з конструкторами та виключеннями

Розглянемо ситуацію, коли виключення прямо чи непрямо викидається конструктором. При виникненні виключення деструктори викликаються лише для повністю сконструйованих локальних об’єктів.

#include<iostream.h>

#include<except.h>

class TDataClass

{public:

TDataClass()

{

cout<<“ TDataClass:: TDataClass()”<<endl;

}

~TDataClass()

{

cout<<“ TDataClass:: ~TDataClass()”<<endl;

}

};

class TBaseClass

{public:

TBaseClass()

{cout<<“ TBaseClass:: TBaseClass()”<<endl;

}

~TBaseClass()

{cout<<“ TBaseClass:: ~TBaseClass()”<<endl;

}

};

class TDerivedClass:public TBaseClass

{ TDataClass data;

public:

TDerivedClass()

{ cout<< “TDerivedClass:: TDerivedClass()”<<endl;

cout<<“викидається виключення”<<endl;

trow “Ой! Щось сталося”;

}

~TDerivedClass()

{ cout<< “TDerivedClass::~ TDerivedClass()”<<endl;}

};

int main(void)

{

try{ TDerivedClass tds;

//. . .

}

catch(const char*msg)

{

cout<<“впіймолось виключення”<<msg<<endl;

return -1;

}

return 0;

}

Результати роботи програми:

TBaseClass:: TBaseClass()

TDataClass:: TDataClass()

TDerivedClass::TDerivedClass()

викидаємо виключення

TDataClass:: ~TDataClass()

TDerivedClass::~ TDerivedClass()

впіймолось виключення: Ой! Щось сталося

Щоб управління виключеннями С++ приносило вигоду, необхідно запакувати ініціалізацію та очистку деякого ресурса відповідно в конструктор та деструктор класу і при виділенні ресурса створювати локальні екземпляри цього класу. Якщо конструктор класу виділяє ресурси кількох типів чи виконує код, який може викинути виключення після того, як ресурс виділений, рекомендується помістити кожен ресурс у свій власний клас. Таким чином, кожен ресурс завжди буде локалізованим у повністю зконструйованому класі.