Исключительные ситуации
Классификация исключительных ситуаций
Режимы компиляции для работы с исключительными ситуациями
Переключение режимов компиляции для перехвата исключений
Инструкции С++ для работы с исключительными ситуациями
Защищённый блок
Механизм работы защищённого блока
Пример выброса исключения (системные исключения)
Возбуждение собственных исключений
Полный формат защищённого блока
Пример выброса исключения (собственные исключения)
Пример выброса исключения (собственные исключения)
Пример выброса исключения (собственные исключения)
Последовательность действий при обработке исключений
Последовательность действий при обработке исключений (продолжение)
Последовательность действий при обработке исключений (продолжение)
Пример обработки исключений (1)
Пример обработки исключений (2)
Пример обработки исключений (3)
Исключения в конструкторах и деструкторах
Пример использования исключений в конструкторе
Свойства исключений в конструкторе
Передача дополнительной информации об исключении
Иерархии исключений
Пример иерархии исключений
Работающие обработчики исключений (пример 1)
Работающие обработчики исключений (пример 2)
Работающие обработчики исключений (пример 3)
Работающие обработчики исключений (пример 4)
Работающие обработчики исключений (пример 5)
Необработанное исключение
Собственная функция аварийного завершения
Преимущества использования исключений
Проблемы
Выброс исключения в конструкторе
Выброс исключений в деструкторе
Exception-safe programming
Код, устойчивый к возникновению исключений
Правило разработки exception-safe кода
Безопасность исключений и вопросы проектирования
Гарантии безопасности исключений
Тонкая обработка системных исключений
Трансляция исключений
Трансляция исключений (продолжение)
Преобразование системных исключений в пользовательские
Преобразование системных исключений в пользовательские (продолжение)
285.89K
Category: programmingprogramming

except

1.

Исключения

2. Исключительные ситуации

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

3. Классификация исключительных ситуаций

Различают два основных типа исключений:
исключения C++;
системные исключения.
Первый тип исключений генерируется в самой
программе инструкцией throw.
Второй тип исключений генерируется операционной
системой.

4. Режимы компиляции для работы с исключительными ситуациями

Для того чтобы обеспечить перехват исключений C++,
необходимо включить режим компиляции /EHsc, а для
перехвата исключений любого типа – режим /EHa.
Кроме того, для перехвата системных исключений,
связанных с обработкой данных с плавающей точкой,
следует включить режим /fp:except.

5. Переключение режимов компиляции для перехвата исключений

6. Инструкции С++ для работы с исключительными ситуациями

Язык C++ включает следующие возможности для
работы с исключениями:
создание защищенных блоков (try-блок) и перехват
исключений (catch-блок);
инициализация исключений (инструкция throw).

7. Защищённый блок

Простейший формат защищенного блока имеет вид
try {операторы_защищенного_блока}
catch(...) {обработчик_исключительной_ситуации}
Многоточие является частью синтаксиса языка!

8. Механизм работы защищённого блока

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

9. Пример выброса исключения (системные исключения)

int x = 0;
try {
cout <<2/x; // Здесь произойдет выброс исключения
// Последующие операторы выполняться не будут
}
catch (...) {
cout << "Division by zero" << endl;
}
Для корректной работы этого примера необходимо
включить режим компиляции /EHa

10. Возбуждение собственных исключений

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

11. Полный формат защищённого блока

try {операторы_защищенного_блока}
catch-блоки
Catch-блок имеет один из следующих форматов:
catch (тип) {обработчик_исключения}
catch (тип идентификатор) {обработчик_исключения}
catch (...) {обработчик_исключения}
Первый формат используется, если нам надо указать
тип перехватываемого исключения, но не нужно
обрабатывать связанное с этим исключением значение
(это достигается при использовании второго формата
оператора catch). Наконец, третий формат оператора
catch позволяет обработать все исключения (в том
числе и системные).

12. Пример выброса исключения (собственные исключения)

try {

throw 0;
//Здесь произойдет выброс исключения
// Последующие операторы выполняться не будут
}
catch (...) {
cout << “Everything fail!” << ‘\n’;
}

13. Пример выброса исключения (собственные исключения)

try {

throw 0;
//Здесь произойдет выброс исключения
// Последующие операторы выполняться не будут
}
catch (int) {
cout << ”Int type exception was thrown!” << ‘\n’;
}
catch (...) {
cout << ”Everything fail!” <<‘\n’;
// этот блок не будет работать
}

14. Пример выброса исключения (собственные исключения)

try {

throw 0;
//Здесь произойдет выброс исключения
// Последующие операторы выполняться не будут
}
catch (int e) {
cout << ”Int type exception was thrown, code is ”
<< e << endl;
}
catch (...) {
cout << ”Everything fail!” << endl;
// этот блок не будет работать
}

15. Последовательность действий при обработке исключений

Создается статическая переменная со значением,
заданным в операторе throw. Она будет
существовать до тех пор, пока исключение не будет
обработано.
Завершается выполнение защищенного try-блока:
раскручивается стек подпрограмм, корректно
уничтожаются объекты, время жизни которых
истекает и т.д.
Выполняется поиск первого из catch-блоков,
который пригоден для обработки созданного
исключения.

16. Последовательность действий при обработке исключений (продолжение)

Поиск catch-блоков ведется по следующим критериям:
тип, указанный в catch-блоке, совпадает с типом
созданного исключения, или является ссылкой на этот
тип;
указатель, заданный в операторе throw, может быть
преобразован по стандартным правилам к указателю,
заданному в catch-блоке.
в операторе throw задано многоточие.
Если нужный обработчик найден, то ему передается
управление и, при необходимости, значение,
вычисленное в операторе throw. Оставшиеся catchблоки игнорируются.

17. Последовательность действий при обработке исключений (продолжение)

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

18. Пример обработки исключений (1)

#include <fstream.h>
class Hello{
public:
Hello(){cout « "Hello!" « endl;}
~Hello(){cout « "Bye!" « endl;}
};
void fl(){
ifstream ifs(“BAD_FILE_NAME");
if (!ifs){
cout « "Генерируем исключение" « endl:
throw "Ошибка при открытии файла“;
}
}
void f2(){
Hello H; // Создаем локальный объект
fl();
// Вызываем функцию, генерирующую
исключение
}
22.04.2026
18

19. Пример обработки исключений (2)

int main(){
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;
}
22.04.2026
19

20. Пример обработки исключений (3)

Результаты выполнения программы:





Входим в try-блок
Hello!
Генерируем исключение
Bye!
Вызван обработчик const char *, исключение Ошибка при открытии файла
После порождения исключения был вызван
деструктор локального объекта, хотя
управление из функции f 1 было передано
обработчику находящемуся в функции main.
Сообщение «Выходим из try-блока» не было
ведено.
22.04.2026
20

21. Исключения в конструкторах и деструкторах

Язык C++ не позволяет возвращать значение
из конструктора и деструктора.
Механизм исключений дает возможность
сообщить об ошибке, возникшей в
конструкторе или деструкторе объекта.
Этот же механизм можно использовать в
функциях, которые не возвращают значений
или должны возвращать значения
определенного типа.
22.04.2026
21

22. Пример использования исключений в конструкторе

const int MaxVectorSize = 32000;
class Vector{
public:
class Size{};
// Класс исключения
Vector(int n){
if (n < 0 || n > MaxVectorSize)
throw Size;
...
}
При использовании класса Vector можно предусмотреть перехват исключений
типа Size.
try{
Vector *p = new Vector(i);
}
catch(Vector::Size){
... // Обработка ошибки размера вектора
}
22.04.2026
22

23. Свойства исключений в конструкторе

Если в конструкторе объекта генерируется
исключение, автоматически вызываются
деструкторы для полностью созданных в этом блоке
к текущему моменту объектов, а также для полей
данных текущего объекта, являющихся объектами,
и для его базовых классов.
◦ Например, если исключение возникло при создании
массива объектов, деструкторы будут вызваны только для
успешно созданных элементов.
Если объект создается в динамической памяти с
помощью операции new и в конструкторе возникнет
исключение, память из-под объекта корректно
освобождается.
22.04.2026
23

24. Передача дополнительной информации об исключении

Для передачи дополнительной информации об возможном исключении можно создать
собственный класс.
class Except{
public:
int type; // тип исключения
char msg[256];
// сообщение для пользователя
Except(int type,char *msg){
this->type= type;
strcpy(this->msg, msg);
}
};
void f1(){

throw Except(1,”Не могу открыть файл”);

throw Except(10,”Деление на 0”);
}
int main(){
try{
f1();
}
catch(Except ex){
switch(ex.type){
case 1:

22.04.2026
case …
24

25. Иерархии исключений

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

26. Пример иерархии исключений

class Matherr{};
class Overflow: public Matherr{}; // Переполнение
class Underflow: public Matherr{}; // Исчезновение порядка
class ZeroDivide: public Matherr{}; // Деление на ноль
class IOerr{};
class Readerr:
public IOerr{};
// Ошибка чтения
class Writerr:
public IOerr{};
// Ошибка записи
class Seekerr:
public IOerr{};
// Ошибка поиска
int main(){
try{

}
catch(IOErr){

}
catch(Overflow){

}
}
22.04.2026
26

27.

Стандартные классы исключений
exception
logic_error
runtime_error
length_error
domain_error
out_of_range
bad_alloc
bad_exception
bad_cast
range_error
bad_typeid
overflow_error
io_base::failure
underflow_error
invalid_argument
27

28.

Выбрасывание исключения (throw)
Вариант 1: использовать простой тип
try
{
if (y == 0) throw std::string("Деление на ноль!");
z = x / y;
}
catch(const std::string& ex)
{
std::cerr << ex;
}
28

29.

Вариант 2: класс std::exception
try
{
if (y == 0) throw std::exception("Деление на ноль!");
z = x / y;
}
catch(std::exception& ex)
{
std::cerr << ex.what();
}
29

30.

Вариант 3: собственный класс
class ExceptionDivideByZero : public std::exception
{
};
try
{
if (y == 0) throw ExceptionDivideByZero();
z = x / y;
}
catch(ExceptionDivideByZero)
{
std::cerr << "Деление на ноль!";
}
30

31.

Catch all
try
{
}
catch(...)
{
std::cerr << "Неизвестная ошибка!";
}
31

32.

Catch-цепочка
try
{
}
catch(std::bad_alloc)
{
}
catch(std::bad_cast)
{
}
32

33.

try
{
}
catch(std::exception)
{
}
catch(...)
{
}
catch(std::bad_alloc)
{
}
// ОШИБКА
33

34.

try
{
}
catch(std::bad_alloc)
{
}
catch(std::exception)
{
}
catch(...)
{
}
// ВЕРНО
34

35.

Повторное выбрасывание исключения
try
{
try
{
// Здесь произошла ошибка выделения памяти
}
catch(std::bad_alloc)
{
// Выдаем сообщение, и перевыбрасываем:
throw;
}
}
catch(std::exception)
{
// Заносим в лог
}
35

36. Работающие обработчики исключений (пример 1)

try { …
try {

throw ”Error!”;
catch (int) {… }
catch (float) {… }
…} //внешний try
catch (char * c) { … }
catch (...) { …}
… } //внутренний try

37. Работающие обработчики исключений (пример 2)

try {

try {

throw ”Error!”;

} //внутренний try
catch (char *) {…
}
catch (float) {…
}

} //внешний try
catch (char * c) {…
}
catch (...) { …
}

38. Работающие обработчики исключений (пример 3)

try {

try {

throw ”Error!”;

} //внутренний try
catch (char *) {…
throw;
}
catch (float) {…
}

} //внешний try
catch (char * c) {…
}
catch (...) { …
}

39. Работающие обработчики исключений (пример 4)

try {

try {

throw ”Error!”;

} //внутренний try
catch (void *) {…
throw;
}
catch (float) {…
}

} //внешний try
catch (char * c) {…
}
catch (...) { …
}

40. Работающие обработчики исключений (пример 5)

try {

try {

throw ”Error!”;

} //внутренний try
catch (void *) {…
throw;
}
catch (float) {…
}

} //внешний try
catch (...) { …
} //ошибочный порядок записи!
catch (char * c) {…
}

41. Необработанное исключение

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

42. Собственная функция аварийного завершения

Можно зарегистрировать с помощью функции
set_terminate свою функцию, которая будет
выполняться перед аварийным завершением работы:
void MyTerminate() {
cout << "An error occured!" << endl;
exit(-1);
}
int main ()
{
set_terminate(MyTerminate);

throw 0;
}

43. Преимущества использования исключений

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

44. Проблемы

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

45. Выброс исключения в конструкторе

При выбросе исключения в теле
конструктора или в списке
инициализации процесс
конструирования экземпляра класса
прерывается и он считается не
созданным
◦ Деструктор для такого класса вызван не
будет
◦ Будут вызваны деструкторы для тех полей
класса, для которых успели выполниться
конструкторы

46.

class A
{
public:
A(std::string const& name)
:m_name(name)
{
std::cout << "A::A(" << m_name << ")\n";
}
~A()
{
std::cout << "A::~A(" << m_name << ")\n";
}
private:
std::string m_name;
};
int main()
{
try
{
B b2("Test", 1000000000);
}
catch (std::bad_alloc const & e)
{
std::cout << "Error: " << e.what() << "\n";
}
return 0;
}
class B
{
public:
B(std::string const& name, size_t size)
:m_a(name)
,m_pData(new int[size])
,m_size(size)
{
std::cout << "B::B(" << m_size << ")\n";
}
~B()
{
delete [] m_pData;
std::cout << "B::~B(" << m_size << ")\n";
}
private:
A m_a;
Нехватка памяти и
size_t m_size;
int * m_pData;
выброс исключения
};
std::bad_alloc
Output:
A::A(Test)
A::~A(Test)
Error: bad allocation

47. Выброс исключений в деструкторе

Не допускайте выброса исключений в
деструкторах объектов
В C++ выброс исключения в
деструкторе приводит к аварийному
завершению работы программы

48. Exception-safe programming

Разработка кода, безопасного к возникновению
исключений
EXCEPTION-SAFE
PROGRAMMING

49. Код, устойчивый к возникновению исключений

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

50.

class CMyString
{
public:
CMyString(const char * str):m_size(strlen(str))
{
m_pChars = new char[m_size + 1];
memcpy(m_pChars, str, m_size);
m_pChars[m_size] = '\0';
}
CMyString(CMyString const& other)
:m_size(other.m_size)
,m_pChars(new char[other.m_size + 1])
{
memcpy(m_pChars, other.m_pChars, m_size + 1);
}
~CMyString()
{
delete [] m_pChars;
}
CMyString& operator=(CMyString const& other)
{
if (this != &other)
{
delete [] m_pChars;
m_size = other.m_size;
m_pChars = new char[other.m_size + 1];
memcpy(m_pChars, other.m_pChars, m_size + 1);
}
return *this;
}
private:
char * m_pChars;
size_t m_size;
};
Код конструктора безопасен к
возникновению исключений
Код конструктора копирования
безопасен к возникновению
исключений
Выброс исключения в операторе
new нарушит целостность
объекта и возможность его
корректного разрушения: в
деструкторе произойдет
повторное удаление массива
m_pChars.

51.

class CMyString
{
public:
CMyString(const char * str):m_size(strlen(str))
{
m_pChars = new char[m_size + 1];
memcpy(m_pChars, str, m_size);
m_pChars[m_size] = '\0';
}
CMyString(CMyString const& other)
:m_size(other.m_size)
,m_pChars(new char[other.m_size + 1])
{
memcpy(m_pChars, other.m_pChars, m_size + 1);
}
~CMyString()
{
delete [] m_pChars;
}
CMyString& operator=(CMyString const& other)
{
if (this != &other)
{
delete [] m_pChars; m_pChars = NULL;
m_size = other.m_size;
m_pChars = new char[other.m_size + 1];
memcpy(m_pChars, other.m_pChars, m_size + 1);
}
return *this;
}
private:
char * m_pChars;
size_t m_size;
};
Код конструктора безопасен к
возникновению исключений
Код конструктора копирования
безопасен к возникновению
исключений
При выбросе исключения объект
станет destructibe, но целостность
объекта будет нарушена для его
последующего использования:
переменная m_size будет
содержать некорректную длину, а
m_pChars будет равен NULL

52.

class CMyString
{
public:
CMyString(const char * str):m_size(strlen(str))
{
m_pChars = new char[m_size + 1];
memcpy(m_pChars, str, m_size);
m_pChars[m_size] = '\0';
}
Код конструктора безопасен к
возникновению исключений
CMyString(CMyString const& other)
:m_size(other.m_size)
,m_pChars(new char[other.m_size + 1])
{
memcpy(m_pChars, other.m_pChars, m_size + 1);
}
~CMyString()
{
delete [] m_pChars;
}
CMyString& operator=(CMyString const& other)
{
if (this != &other)
{
char * pNewChars = new char[other.m_size + 1];
m_size = other.m_size;
delete [] m_pChars; m_pChars = pNewChars;
memcpy(m_pChars, other.m_pChars, m_size + 1);
}
return *this;
}
private:
char * m_pChars;
size_t m_size;
};
Код конструктора копирования
безопасен к возникновению
исключений
При выбросе исключения не
происходит утечек памяти, а
объект остается в том же
состоянии, в каком он был до
вызова оператора =
Безопасность оператора
присваивания достигнута

53.

class CMyString
{
public:
CMyString(const char * str):m_size(strlen(str))
{
m_pChars = new char[m_size + 1];
memcpy(m_pChars, str, m_size);
m_pChars[m_size] = '\0';
}
CMyString(CMyString const& other)
:m_size(other.m_size)
,m_pChars(new char[other.m_size + 1])
{
memcpy(m_pChars, other.m_pChars, m_size + 1);
}
~CMyString()
{
delete [] m_pChars;
}
CMyString& operator=(CMyString const& other)
{
if (this != &other)
{
CMyString copy(other);
std::swap(m_pChars, copy.m_pChars);
std::swap(m_size, copy.m_size);
}
return *this;
}
private:
char * m_pChars;
size_t m_size;
};
Код конструктора безопасен к
возникновению исключений
Код конструктора копирования
безопасен к возникновению
исключений
При выбросе исключения не
происходит утечек памяти, а
объект остается в том же
состоянии, в каком он был до
вызова оператора =, кроме того,
код оператора = стал более
понятным
Безопасность оператора
присваивания достигнута

54. Правило разработки exception-safe кода

Правило разработки exceptionsafe кода
В каждом методе или функции
выделите код, который может
выбрасывать исключения
Реорганизуйте код так, чтобы
исключения не выбрасывались в
процессе изменения состояния
программы (или объекта)
Лишь после того, как задача
выполнена, можно изменять состояние
программы используя операции, не

55.

class CStringStack
{
struct Item
{
Item(std::string const& str, Item * p)
:data(str),pNext(p)
{
}
std::string data;
Item * pNext;
};
public:
bool IsEmpty()const
{
return (m_pTop == NULL);
}
std::string Pop()
{
if (IsEmpty())
{
throw std::logic_error("Stack is empty");
}
std::string result = m_pTop->data;
Item * pItem = m_pTop;
m_pTop = m_pTop->pNext;
delete pItem;
return result;
}
private:
Item * m_pTop;
};
Код конструктора безопасен к
возникновению исключений
Создание копии строки может
привести к выбросу исключения
При этом вытолкнутый элемент
окажется безвозвратно потерян
– результат возвращен не будет,
а элемент из стека уже удален

56.

class CStringStack
{
struct Item
{
Item(std::string const& str, Item * p)
:data(str),pNext(p)
{
}
std::string data;
Item * pNext;
};
public:
bool IsEmpty()const
{
return (m_pTop == NULL);
}
void Pop(std::string & result)
{
if (IsEmpty())
{
throw std::logic_error("Stack is empty");
}
result = m_pTop->data;
Item * pItem = m_pTop;
m_pTop = m_pTop->pNext;
delete pItem;
}
private:
Item * m_pTop;
};
Код конструктора безопасен к
возникновению исключений
Такое решение решает проблему,
однако фактически метод выполняет
две задачи:
•Выталкивает элемент с вершины
стека
•Возвращает вытолкнутое значение
При проектировании программных
систем следует стремиться к тому,
чтобы каждый модуль, класс и
функция имели единственную четко
заданную сферу ответственности

57.

class CStringStack
{
struct Item
{
Item(std::string const& str, Item * p)
:data(str),pNext(p)
{
}
std::string data;
Item * pNext;
};
public:
bool IsEmpty()const
{
return (m_pTop == NULL);
}
void Pop()
{
if (IsEmpty())
throw std::logic_error("Stack is empty");
Item * pItem = m_pTop;
m_pTop = m_pTop->pNext;
delete pItem;
}
std::string GetTop()const
{
if (IsEmpty())
throw std::logic_error("Stack is empty");
return m_pTop->data;
}
private:
Item * m_pTop;
};
Код конструктора безопасен к
возникновению исключений

58. Безопасность исключений и вопросы проектирования

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

59. Гарантии безопасности исключений

Базовая гарантия безопасности
◦ Скажи Нет! утечкам ресурсов
◦ Безопасное разрушение и использование
объекта
◦ Согласованное (не обязательно
предсказуемое) состояние объекта
Строгая гарантия безопасности
◦ Поддержка транзакционной семантики
выполнения методов «commit-or-rollback» объект не меняет своего состояния при
выбрасывании исключения
Гарантия отсутствия исключений
◦ Функция или метод ни при каких условиях не
выбрасывает исключений

60. Тонкая обработка системных исключений

Режим компиляции /EHa позволяет перехватывать и
обрабатывать системные исключения, возникающие в
процессе работы программы. Однако обработчик
таких исключений помещается в блок catch (…) и не
дает возможности определить, какое именно
исключение возникло.
Для более детальной обработки системных
исключений можно воспользоваться механизмом
трансляции исключений

61. Трансляция исключений

Транслятор исключений – пользовательская callbackфункция, прототип которой имеет вид
void MyTranslator(unsigned err_code,
_EXCEPTION_POINTERS *p);
Параметр err_code обозначает тип исключительной
ситуации (константа
EXCEPTION_INT_DIVIDE_BY_ZERO, например,
обозначает попытку деления на ноль в целочисленной
арифметике, а константа
EXCEPTION_ACCESS_VIOLATION – попытку обратиться
к запрещенному адресу памяти).
Указатель p содержит адрес структуры, содержащей
дополнительную информацию об исключении.

62. Трансляция исключений (продолжение)

Написанный транслятор необходимо зарегистрировать
вызовом функции
_set_se_translator(MyTranslator);
После этого транслятор получает управление при
каждом выбросе системного исключения.
Транслятор – не обработчик исключения!
По завершению его работы выполняется стандартные
действия по обработке исключения!

63. Преобразование системных исключений в пользовательские

void MyTranslator(unsigned err_code,
_EXCEPTION_POINTERS *p) {
throw err_code;
}
Теперь в блоке catch(unsigned) можно выполнить более
тонкую обработку системных исключений:
int main() {
int x = 0;
int *px = NULL;
_set_se_translator(MyTranslator);
try {
//
cout << 2/x;
*px=0;
}

64. Преобразование системных исключений в пользовательские (продолжение)

catch (unsigned e) {
switch (e) {
case EXCEPTION_INT_DIVIDE_BY_ZERO:
cout << "Division by zero" << endl;
break;
case EXCEPTION_ACCESS_VIOLATION:
cout << "Invalid pointer assignement" << endl;
break;
}
}
return 0;
}
English     Русский Rules