Правильно ли работает удаление с полиморфизмом?

BaseClass * p = new DerivedClass();
delete p;

Я знаю, что вторая строка вызовет деструктор базового класса, если у него нет виртуального деструктора, и деструктора производного класса, если он есть, но delete должным образом освободит память (скажем, объект BaseClass занимает 8 байтов пространства и DerivedClass one 12 - освободит ли он 8 или 12 байт) и избавится от объекта в любом случае?


person NPS    schedule 11.05.2013    source источник
comment
Вы знакомы с семантикой _1 _ / _ 2_?   -  person Carl Norum    schedule 11.05.2013
comment
Re: вызвать деструктор базового класса - возможно. Если вы удаляете объект производного типа с помощью указателя на базовый тип, а базовый тип не имеет виртуального деструктора, поведение не определено. Он может вызвать деструктор базового класса, но это не обязательно.   -  person Pete Becker    schedule 11.05.2013
comment
@NPS Обратите внимание, что стоит упомянуть, что в случае, если вы создали объект DerivedClass в стеке (т.е. - DerivedClass d;), тогда совершенно не имеет значения, является ли BaseClass Dtor виртуальным или нет - два из них (оба из Dtor) будут вызываться в обратном порядке по отношению к их построению (то есть - DerivedClass, а затем BaseClass).   -  person Guy Avraham    schedule 23.01.2017


Ответы (2)


Что ж, в случае, если у него есть деструктор virtual, конечно, объект будет уничтожен, а память будет освобождена, как ожидалось. Если у него нет virtual деструктора, поведение не определено.

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

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

person Joseph Mansfield    schedule 11.05.2013

Если деструктор не виртуальный, delete не удалит производный класс.

Я пробовал это:

#include<iostream>

using namespace std;

class Base {
public:
    Base() {
        cout<<"Creating base."<<endl;
    }

    ~Base() {
        cout<<"Killing base."<<endl;
    }
};

class Derived: public Base {
public:
    Derived() {
        cout<<"Creating derived."<<endl;
    }

    ~Derived() {
        cout<<"Killing derived."<<endl;
    }
};

int main() {
    Base *p = new Derived();
    delete p;
    return 0;
}

Компилируя на G ++ 4.7.3 (оптимизация по умолчанию), получаю

Creating base.
Creating derived.
Killing base.

Обратите внимание на отсутствие Killing derived.

person Anubhav C    schedule 11.05.2013
comment
Насколько я понимаю, деструктор - это только средство ручной очистки до того, как объект будет фактически уничтожен программой. Так что поправьте меня, если я ошибаюсь, но я думаю, что этот код ничего не доказывает. - person NPS; 11.05.2013
comment
delete одновременно запускает деструктор и освобождает память, если память выделяется в куче (например, когда вы выделяете память с помощью new). Если деструктор не вызывается, я думаю, можно с уверенностью сказать, что память тоже не освобождается. - person Anubhav C; 11.05.2013
comment
@AnubhavC Я продолжил ваш ответ и добавил еще несколько моментов, которые следует учитывать. Если вас интересует: stackoverflow.com/a/41801254/1971003 - person Guy Avraham; 23.01.2017