Освобождается ли память, когда я создаю исключение?

StackOverflow https://stackoverflow.com/questions/1306094

Вопрос

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

Рассмотрим следующий пример:

class B
{
public:
    B()
    {
        cout << "B::B()" << endl;
        throw "B::exception";
    }

    ~B()
    {
        cout << "B::~B()" << endl;          
    }
};

void main()
{
    B *o = 0;
    try
    {
        o = new B;
    }
    catch(const char *)
    {
        cout << "ouch!" << endl;
    }
}

Что происходит с поврежденной памятью o, протекает ли она?Улавливает ли CRT исключение конструктора и освобождает ли память?

Ваше здоровье!
Богатый

Это было полезно?

Решение

Призыв к

new B();

решает в двух вещах:

  • выделение с помощью оператора new() (либо глобального, либо специфичного для класса, потенциально для размещения с синтаксисом new (xxx) B())
  • вызов конструктора.

Если конструктор выбрасывает, вызывается соответствующий оператор delete.Случай, когда соответствующее удаление является размещающим, является единственным случаем, когда оператор удаления размещения вызывается без синтаксиса ::operator delete() . delete x; или delete[] x; не вызывайте операторы placement delete, и для их вызова не существует синтаксиса, похожего на placement new.

Обратите внимание, что в то время как деструктор B будет не при вызове уже созданные подобъекты (члены или B и базовые классы B) будут уничтожены перед вызовом оператора delete.Конструктор, который не вызывается, является конструктором для B.

Другие советы

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

В этом случае ваш объект o фактически не создается, и память, выделенная с помощью new, освобождается.Таким образом, деструктор не вызывается.Так что вам НЕ нужно звонить:

delete o;

Интересным шаблоном проектирования является RAII - получение ресурсов является инициализацией.В этом шаблоне вы используете конструктор для инкапсуляции получения ресурса и освобождения ресурса в деструкторе.Если ресурс не может быть получен, вы добавляете конструктор - очень похоже на ваш пример.Таким образом, если у вас есть действительный объект, у вас есть ресурс.

Если объект создан, значит, вы успешно приобрели ресурс.Это означает, что на протяжении всего срока службы объекта ресурсом владеете вы.Когда объект удаляется, ресурс освобождается.Если объект никогда не будет создан, значит, вы никогда не приобретали ресурс.Смотрите википедию:

http://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization

Из стандарта C ++ 2003 5.3.4/17 - Новый:

Если какая-либо часть описанной выше инициализации объекта завершается выдачей исключения и может быть найдена подходящая функция освобождения, функция освобождения вызывается для освобождения памяти, в которой создавался объект, после чего исключение продолжает распространяться в контексте нового выражения.Если не удается найти однозначную соответствующую функцию освобождения, распространение исключения не приводит к освобождению памяти объекта.[Примечание:Это уместно, когда вызываемая функция выделения не выделяет память;в противном случае это, скорее всего, приведет к утечке памяти.]

Таким образом, утечка может быть, а может и не быть - это зависит от того, можно ли найти соответствующий освобождающий параметр (что обычно имеет место, если только оператор new / delete не был переопределен).В случае, когда имеется подходящий освободитель, компилятор отвечает за подключение к нему вызова, если конструктор выдает ошибку.

Обратите внимание, что это более или менее не связано с тем, что происходит с ресурсами, приобретенными в конструкторе, о чем шла речь в моей первой попытке найти ответ - и это вопрос, который обсуждается во многих часто задаваемых вопросах, статьях и публикациях.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top