Не виртуальный тривиальный деструктор + Наследование - PullRequest
2 голосов
/ 12 мая 2011

Учитывая, что классу и всем его подклассам требуется не более деструктора по умолчанию для освобождения своих ресурсов, если они хранятся в переменной точного типа (или указателя на точный тип), может ли утечка памяти подкласса, если на нее ссылается база указатель класса и затем удален этим указателем?

Пример:

#include <memory>

class A {
};

class B : public A {
public:
    B () : pInt(new int) {}
    auto_ptr<int> pInt; // this is what might leak... possibly more will though
};

void will_this_leak () {
    A *pA = new B();
    delete pA;
}

Ответы [ 4 ]

9 голосов
/ 12 мая 2011

«Утечка памяти»? Почему вы конкретно говорите об утечке памяти?

Код, который вы разместили, производит неопределенное поведение . В этом случае может произойти все что угодно: утечка памяти, форматирование жесткого диска, сбой программы и т. Д.

P.S. Я знаю, что существует популярная городская легенда о том, что полиморфное разрушение без виртуального деструктора «может привести к утечке памяти». Я не знаю, кто изобрел эту чепуху и почему они решили использовать «утечку памяти» в качестве основного сценария того, что может произойти. На самом деле поведение в этом случае не имеет абсолютно никакого отношения к «утечке памяти». Поведение просто не определено.

С практической точки зрения, в вашем конкретном случае довольно очевидно, что у деструктора вашего auto_ptr нет реальной возможности вызвать его, поэтому память, принадлежащая этому auto_ptr, непременно будет утечка. Но опять же, это наименьшая из проблем этого кода.

4 голосов
/ 12 мая 2011

Неважно, могут они течь или нет. Стандарт C ++ говорит, что удаление производного класса через указатель базы является неопределенным поведением, если в базе нет виртуального деструктора. В частности, из 5.3.5 / 3:

В первом варианте (удаление объекта), если статический тип операнд отличается от своего динамического типа, статический тип должен быть базовый класс динамического типа операнда и статический тип должен иметь виртуальный деструктор или поведение не определено.

Так что, как только вы сделали такое удаление, ваша программа находится в неопределенном состоянии, и все вопросы об утечках неактуальны.

1 голос
/ 12 мая 2011

Код на данный момент показывает undefined-поведение .

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

#include <memory>

class A {

    public :
    virtual ~A() {} // This makes the derived sub-object destruction first

};

class B : public A {
public:
    B () : pInt(new int) {}
    auto_ptr<int> pInt; 

    /* There is no need to write any custom destructor
       in this case. auto_ptr will effectively handle deallocating
       the acquired resources from free store.
    */
};

void will_this_leak () {
    A *pA = new B();
    delete pA;
}

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

1 голос
/ 12 мая 2011

Да, это будет утечка.Когда вы удаляете A *, он вызывает ~ A ().Поскольку ~ A () не является виртуальным, он не будет знать, что ~ B () тоже нуждается в вызове.

Предполагая, конечно, что B наследуется от A. Я предполагаю, что это опечатка в вашем вопросе- код, как он есть, не будет компилироваться:)

...