2015-12-28 3 views
3

У меня есть сомнения по поводу вопроса, который я часто спрашиваю себя, это положение:Наследование C++: отсутствует ли виртуальный деструктор для утечки памяти?

Два класс, не виртуального деструктор

class Base 
{ 
    int myInt; 
}; 

class Derived : public Base 
{ 
    int myIntDerived; 
}; 

int main() 
{ 
    Base *base = new Derived; 
    Derived *derived = new Derived; 

    delete base; 
    delete derived; 
} 

Правильно ли сказать, что первое удаление вызывает некоторое время утечки памяти второй - прекрасный?

+0

На практике это все работает и без каких-либо утечек памяти. Теоретически это неопределенное поведение, и все может случиться. На практике, утечка памяти, о которой вы спрашиваете, происходит, когда 'Derived' владеет выделенной памятью отдельно. – JSF

ответ

13

Можно ли сказать, что первое удаление вызывает утечку памяти, а второе - в порядке?

Второй вариант действительно прекрасен, но ваше первое утверждение не совсем верно.

Формально удаление объекта с помощью указателя на базовый подобъект, который имеет не виртуальный деструктор, имеет неопределенное поведение. Возможна утечка немыслима, но не требуется. Фактически, в вашем случае, поскольку ни derived, ни любой из его объектов-членов не выделяют динамическую память, которая будет освобождена в деструкторе, вероятно, утечки не произойдет.

Произошла ли утечка памяти или нет, это в наименьшей степени ваша проблема, когда ваша программа имеет неопределенное поведение.

+3

Почему это вниз? Ответ верный и полный. –

+1

@KerrekSB Я предполагаю, что жизнь нечестна. Мы можем только повысить его, чтобы компенсировать. – YSC

10

Это неопределенное поведение, которое может, в самом деле, привести к утечке памяти:
Стандарт C++, [expr.delete], пункт 3 [ISO/IEC 14882-2014], гласит:

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


Поскольку ни один деструктор ни в одном Base ни Derived не определяется пользователем, по умолчанию деструктор добавляется компилятором. Эти деструкторы не являются virtual.

base Поскольку это Base*, delete base вызывает деструктор базового класса, который является Неопределенное поведение. В конкретных условиях это приводит к утечке памяти при работе с ресурсами; в вашем случае, поскольку ваши классы содержат только POD, я бы сказал, что утечки нет.

Для того, чтобы зафиксировать утечку памяти, необходимо определить виртуальный деструктор для классов, предназначенных для наследования:

struct Base 
{ 
    virtual ~Base() {} 
    int myInt; 
}; 

struct Derived : Base 
{ 
    int myIntDerived; 
}; 

int main() 
{ 
    Base *base = new Derived; 
    Derived *derived = new Derived; 

    delete base; // OK 
    delete derived; // OK 
}