Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КП - 2 часть - Лекция 2. Исключительные ситуаци...docx
Скачиваний:
1
Добавлен:
01.07.2025
Размер:
342 Кб
Скачать
☆

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

Не нужно писать код по обработке ошибок.

Код алгоритма не загромождается кодом по обработке ошибок: его легко понимать и сопровождать.

Исключения не проигнорируешь в отличие от кодов ошибок.

Исключения легко получать из глубоко вложенных функций. Не нужно менять интерфейс функций, чтобы они возвращали какой-то код, достаточно обернуть вызов в try catch.

2.3 Какие есть проблемы с исключениями в С++

Утечки ресурсов и памяти. В С++ нет автоматического сборщика мусора. Поэтому объекты операционной системы требуется явно освобождать, как и память, выделенную динамически. В другие языки добавили механизмы, которые позволяют про это почти не думать – блок finally и сборщик мусора. К подходу как правильно писать код, приходится себя приучивать.

Пример:

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

Еще одна проблема:

Foo(new Test(), new Test2())

Такой код развернется во что-то такое:

Test* test = new Test();

Test2* test2 = new Test2();

Foo(test, test2)

Если new Test2() бросит исключение, то будут утечки: Test никто никогда не очистит...

Исключения в конструкторах. Если исключение произошло в конструкторе, то деструктор для объекта не вызовется, поскольку объект не создан до конца (только для базовых классов вызовется).

Пример:

#include "stdafx.h"

#include <stdio.h>

#include <exception>

#include <iostream>

#include "Person.h"

using namespace std;

class Base

{

public:

virtual ~Base()

{

cout << "Base destructor called\n";

}

};

class Epicness : public Base

{

public:

Epicness(int argument)

{

if (argument < 1)

throw std::exception("Argument is invalid.");

}

~Epicness()

{

cout << "Epicness destructor called\n";

}

};

int main()

{

Epicness* epic = NULL;

try

{

epic = new Epicness(-1);

}

catch (const std::exception& e)

{

delete epic;

}

delete epic;

system("pause");

return 0;

}

Вывод:

Base destructor called

2.4 Пример 2. Исключение и память, проброс

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

Пример:

#include "stdafx.h"

#include <stdio.h>

#include <exception>

#include <iostream>

#include "Person.h"

using namespace std;

void DoSomething()

{

throw std::exception("File is missing."); // некоторая ошибка в бизнес-логике, например файл не найден. Бросаем исключение.

}

void ProcessFile()

{

char* fileContent = new char[100];

try

{

DoSomething();

// бизнес-логика, которая может бросать исключения.

}

catch (...) // мы не можем обработать исключение,

// но нам важно почистить память, выделенную динамически.

{

delete[] fileContent; // чистим ресурсы, за которые отвечаем

throw; // пробрасываем брошенное исключение дальше

}

delete[] fileContent;

}

int main()

{

try

{

ProcessFile();

}

catch (const std::exception& e)

{

cerr << e.what() << endl;

}

system("pause");

return 0;

}

Как видите, код, который выделял динамическую память, отвечает и за ее очистку - в нем находится и код по ее очистке. Очистка произойдет и в случае исключений. После того, как код сделал очистку, он возобновляет исключение. Сама обработка исключительной ситуации происходит в main, на самом высоком уровне.

Более продвинутый подход – использовать умные указатели. О них речь пойдет в следующих лекциях.

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

Нельзя бросать исключения в деструкторах.

3 Приближение

3.1 Спецификация исключений

В язык добавили возможность добавлять для методов и подпрограмм информацию, какие исключения бросаются. Идею, насколько я понимаю, взяли из Java. Идея не выстрелила. От нее отказались.

3.2 Обработка неожидаемых исключений

По-умолчанию, когда происходит исключение, приложение закрывается. Однако этот механизм можно переопределить, например, не закрывать приложение, а продолжить его выполнение. Идея в С++ не выстрелила, поскольку ее поведение сильно зависит от компилятора. Однако в других языках программирования она применяется.

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