Как виртуальные деструкторы работают?

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

class Base
{
  virtual push_elements()
  {}
};

class Derived:public Base
{
vector<int> x;
public:
   void push_elements(){ 
      for(int i=0;i <5;i++)
         x.push_back(i); 
   }
};

void main()
{
    Base* b = new Derived();
    b->push_elements();
    delete b;
}

Инструмент средства проверки границ сообщил об утечке памяти в векторе производного класса. И я выяснил, что деструктор не является виртуальным, и деструктор производного класса не называют. И это удивительно было зафиксировано, когда я сделал деструктор виртуальным. Разве вектор не освобожден автоматически, даже если деструктор производного класса не называют? Это - причуда в инструменте BoundsChecker или является моим пониманием виртуального деструктора неправильно?

6
задан Rob Kennedy 27 April 2010 в 15:39
поделиться

7 ответов

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

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

15
ответ дан 8 December 2019 в 03:26
поделиться

Если деструктор не виртуальный, будет вызван деструктор Base. Базовый деструктор очищает базовый объект и завершает работу. Деструктор базового объекта не может знать о производном объекте, это должен быть вызываемый производный деструктор, и способ сделать это, как и с любой функцией, - сделать деструктор виртуальным.

1
ответ дан 8 December 2019 в 03:26
поделиться

В C ++ тривиальный деструктор представляет собой рекурсивно определенную концепцию - это деструктор, который компилятор написал для вас, когда каждый член класс (и каждый базовый класс) имеет тривиальный деструктор. (Аналогичная концепция называется тривиальным конструктором.)

Когда объект с нетривиальным деструктором включается в объект (например, вектор в вашем примере), то деструктор внешнего объекта (например, ваш Производный ) уже не является тривиальным. Несмотря на то, что вы не писали деструктор, компилятор C ++ автоматически написал деструктор, который вызывает деструкторы любых членов, имеющих деструкторы.

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

1
ответ дан 8 December 2019 в 03:26
поделиться

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

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

2
ответ дан 8 December 2019 в 03:26
поделиться

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

8
ответ дан 8 December 2019 в 03:26
поделиться

Из C ++ FAQ Lite: "Когда мой деструктор должен быть виртуальным?" Прочтите это здесь . (Кстати, C ++ FAQ Lite - отличный источник для всех ваших вопросов, связанных с C ++).

1
ответ дан 8 December 2019 в 03:26
поделиться

Деструктор - это функция-член класса, имя которого совпадает с именем класса, и ему предшествует знак тильды (~). Деструктор используется для уничтожения объекта класса, когда объект выходит за пределы области видимости, или вы можете сказать, что вся очистка от разрушения класса должна выполняться в деструкторе. Вся память, выделяемая во время построения объекта в классе, разрушается (или освобождается память), когда объект выходит за пределы области видимости.

Дополнительные сведения см. В примере на BoundsCheck

0
ответ дан 8 December 2019 в 03:26
поделиться
Другие вопросы по тегам:

Похожие вопросы: