- •2 Часть
- •1 Приближение
- •1.1 Бросание(генерация) исключений
- •1.2 Пример 1. Поддержка инкапсуляции
- •1.3 Ловля исключений
- •2 Приближение
- •2.1 Развитие способов обработки ошибок
- •1. Хочется, чтобы приложение как можно быстрее упало и не успело сделать ничего плохого.
- •2. Хочется, чтобы перед своей кончиной приложение напечатало нечто, позволяющее понять, что не так.
- •2.2 Преимущества использования исключений
- •2.4 Пример 2. Исключение и память, проброс
- •3.3 Отладка и исключения в Visual Studio. Stack trace
- •3.4 Как развивался концепт с исключениями дальше?
- •3.4.2 Сборщик мусора
- •3.5 Общие замечания по созданию исключительных ситуаций
- •3.6 Код всегда должен писаться, чтобы быть устойчивым к исключениям [1]
3.3 Отладка и исключения в Visual Studio. Stack trace
Для того, чтобы проводить отладку в Visual Studio исключительных ситуаций, нужно сделать, чтобы отладчик останавливал выполнение приложения, когда происходит исключение.
Давайте теперь запустим такую программу.
#include "stdafx.h"
#include <stdio.h>
#include <exception>
#include <iostream>
#include <Windows.h>
using namespace std;
void SendEmail()
{
throw std::exception("Cannot send e-mail. Internet connection is missing.");
}
void SendEmailFailover()
{
const int triesCount = 10;
const int waitBetweenTriesMsec = 100;
for (int i = triesCount; i > 0; i--)
{
try
{
SendEmail();
break; // выходим, если получилось.
}
catch (...) // мы не можем обработать исключение,
// но нам важно почистить память, выделенную динамически.
{
if (i > 1)
{
Sleep(waitBetweenTriesMsec);
}
else
{
throw;
}
}
}
}
int main()
{
try
{
SendEmailFailover();
}
catch (const std::exception& e)
{
cerr << e.what() << endl;
system("pause");
return 1;
}
system("pause");
return 0;
}
Когда произошло исключение, мы можем посмотреть, это место автоматически показывается.
Чтобы остановить приложение, нажимаем Break.
Теперь можно пройтись по коду и посмотреть переменные.
Давайте сначала изучим окно Call Stack. Если это окно не видно, то нажимаем.
В этом окне серые строчки – это вызовы подпрограмм, для которых нету исходного кода. Черные – строки, для которых исходный код есть. Как видно, main вызвала SendEmailFailover, эта подпрограмма вызвала SendEmail, SendEmail вызвала подпрограмму по вызову исключения из отладочной версии MSVCR библиотеки, та в свою очередь попросила операционную систему осуществить этот вызов. Попробуйте 2 раза понажимать на черные записи. Должен происходить переход к строчкам кода, которые исполнялись, когда наступила исключительная ситуация. Также можно увидеть значения переменных.
3.4 Как развивался концепт с исключениями дальше?
3.4.1 finally
Во многих языках появилось ключевое слово finally. Это дополнительный блок, который напрямую занимается очисткой ресурсов и отрабатывает всегда, независимо от того было или не было исключение, и какой бы код не происходил в секции catch.
Уходит необходимость дублировать код по очистке выделяемых ресурсов. Такой код
void ProcessFile()
{
char* fileContent = new char[100];
try
{
DoSomething();
// бизнес-логика, которая может бросать исключения.
}
catch (...) // мы не можем обработать исключение,
// но нам важно почистить память, выделенную динамически.
{
delete[] fileContent; // чистим ресурсы, за которые отвечаем
throw; // пробрасываем брошенное исключение дальше
}
delete[] fileContent;
}
превращается в такой
void ProcessFile()
{
char* fileContent = new char[100];
try
{
DoSomething();
}
finally
{
delete[] fileContent;
}
}
3.4.2 Сборщик мусора
Во многих языках появилась сборщик мусора. Когда на объект никто не ссылается, он автоматически уничтожается сборщиком мусора. Код становится еще короче.
void ProcessFile()
{
char* fileContent = new char[100];
try
{
DoSomething();
}
finally
{
delete[] fileContent;
}
}
превращается в
void ProcessFile()
{
char* fileContent = new char[100];
DoSomething();
}
3.4.3 «Умные указатели» в С++
Кусочек памяти оборачивается в «умный указатель», который сам удалит его, как только он выйдет за пределы видимости. Код выглядит как-то так
void ProcessFile()
{
УмныйУказатель<char*> fileContent(new char[100], delete[]);
DoSomething();
}
