Исключения. Высвобождение объектов в исключениях

В этой статье объясняется необходимость и метод освобождения объектов при возникновении исключения. Разделы включают:

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

Это можно сделать двумя основными способами.

  • Обработайте исключения локально с помощью 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 могут вызывать исключения.

Дополнительные сведения см. в разделе "Исключения: перехват и удаление исключений".

См. также

Обработка исключений