Исключения. Высвобождение объектов в исключениях
В этой статье объясняется необходимость и метод освобождения объектов при возникновении исключения. Разделы включают:
Исключения, создаваемые платформой или приложением, прерывают обычный поток программы. Таким образом, очень важно следить за объектами, чтобы правильно удалить их в случае возникновения исключения.
Это можно сделать двумя основными способами.
Обработайте исключения локально с помощью
try
иcatch
ключевое слово, а затем уничтожайте все объекты с помощью одной инструкции.Удалите любой объект в блоке
catch
, прежде чем вызывать исключение за пределами блока для дальнейшей обработки.
Эти два подхода показаны ниже в качестве решений для следующего проблематичного примера:
void SomeFunc() // Problematic code
{
CPerson* myPerson = new CPerson;
// Do something that might throw an exception.
myPerson->SomeFunc();
// Now destroy the object before exiting.
// If SomeFunc above throws an exception this code will
// not be reached and myPerson will not be deleted.
delete myPerson;
}
Как описано выше, не будет удалено, myPerson
если исключение создается SomeFunc
. Выполнение переходит непосредственно к следующему внешнему обработчику исключений, обходя выход нормальной функции и код, который удаляет объект. Указатель на объект выходит из область, когда исключение покидает функцию, а память, занятая объектом, никогда не будет восстановлена до тех пор, пока программа запущена. Это утечка памяти; он будет обнаружен с помощью диагностика памяти.
Обработка исключения локально
Парадигма try/catch предоставляет оборонительный метод программирования для предотвращения утечки памяти и обеспечения уничтожения объектов при возникновении исключений. Например, пример, показанный ранее в этой статье, может быть перезаписан следующим образом:
void SomeFunc()
{
CPerson* myPerson = new CPerson;
try
{
// Do something that might throw an exception.
myPerson->SomeFunc();
}
catch (CException* e)
{
// Handle the exception locally
e->Delete();
}
// Now destroy the object before exiting.
delete myPerson;
}
В этом новом примере настраивается обработчик исключений для перехвата исключения и его локальной обработки. Затем он завершает функцию обычно и уничтожает объект. Важным аспектом этого примера является то, что контекст для перехвата исключения устанавливается с блоками try/catch . Без локального кадра исключений функция никогда не будет знать, что исключение было вызвано и не будет иметь возможности выйти нормально и уничтожить объект.
Создание исключений после уничтожения объектов
Другой способ обработки исключений — передать их в следующий внешний контекст обработки исключений. catch
В блоке можно выполнить очистку локально выделенных объектов, а затем вызвать исключение для дальнейшей обработки.
Вызываемая функция может или не нуждается в освобождении объектов кучи. Если функция всегда освобождает объект кучи перед возвратом в обычном случае, функция также должна освободить объект кучи перед вызовом исключения. С другой стороны, если функция обычно не освобождает объект перед возвратом в обычном случае, необходимо решить, следует ли решить, должен ли объект кучы быть освобожден.
В следующем примере показано, как можно очистить локально выделенные объекты:
void SomeFunc()
{
CPerson* myPerson = new CPerson;
try
{
// Do something that might throw an exception.
myPerson->SomeFunc();
}
catch (CException* e)
{
e->ReportError();
// Destroy the object before passing exception on.
delete myPerson;
// Throw the exception to the next handler.
throw;
}
// On normal exits, destroy the object.
delete myPerson;
}
Механизм исключения автоматически освобождает объекты фрейма; Деструктор объекта кадра также называется.
При вызове функций, которые могут вызывать исключения, можно использовать блоки try/catch , чтобы убедиться, что вы перехватываете исключения и имеете возможность уничтожить созданные вами объекты. В частности, следует учитывать, что многие функции MFC могут вызывать исключения.
Дополнительные сведения см. в разделе "Исключения: перехват и удаление исключений".