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

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();

}