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

Этот вопрос выглядит как обсуждение в Виртуальный деструктор: нужен ли он когда динамически не выделяется память?

В экзаменационном вопросе меня спросили:
Определить какой базовый класс, который поддерживает указатели на динамически распределенную память?

Я ответил:
— Конструктор копирования и оператор присваивания (чтобы убедиться, что НЕ копируются только указатели … например, глубокое копирование), и деструктор (для освобождения выделенной памяти)

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

0

Решение

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

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

5.3.5

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

6

Другие решения

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

Base *pointer_to_base_class = new Derived;
delete pointer_to_base_class;

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

5

Они не на 100% правильные. Виртуальный деструктор является обязательным, если

  1. иерархия классов используется с динамическим полиморфизмом И
  2. производные объекты уничтожаются указателем на базу.

В противном случае не виртуальный деструктор в порядке. Но в большинстве случаев, даже если предназначен только № 1, это хороший способ сделать деструктор виртуальным независимо от № 2.

5

В рамках стандарта большинство иерархий наследования имеют виртуальный деструктор в своей основе; тем не мение, sub_match определяется для публичного наследования от std::pair<BidirectionalIterator, BidirectionalIterator> и как таковой он может владеть динамически распределенной памятью. В смежной области, match_results не требуется, но обычно реализуется для общего наследования от std::vector<...> который определенно выделяет память.

Ваш экзаменатор не совсем неверен, но акцент на динамически распределенной памяти — красная сельдь, которая выдает беспокойство невежество стандарта; в то время как в большинстве реализаций удаление производного типа указателем на базовый тип без виртуального деструктора приведет к разрушению нарезанного объекта, в соответствии со стандартом это неопределенное поведение.

1

Добавление к другим ответам: Вы также можете представить себе ситуацию, когда вам нужен общий базовый класс, но у вас нет для этого реальных функций интерфейса. Но если вам нужна поддержка RTTI и динамического приведения, вам нужна виртуальная функция в вашем классе. Деструктор может быть только этой функцией.

Например, представьте, что вы выздоравливающий Java-программист и настаиваете, что все Object, Вы можете запустить свою первую программу на C ++ следующим образом:

class Object
{
public:
virtual ~Object() { }
};

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

Если вы также думаете, что Object должен быть абстрактным, вы можете даже сделать деструктор чисто виртуальным:

class Object { public: virtual ~Object() = 0; }; Object::~Object() { }

0

Чтобы найти здесь все хорошие ответы, рекомендуется объявить виртуальный деструктор, чтобы обеспечить надлежащую очистку, когда класс должен быть подклассами, чтобы сформировать иерархию и вы хотите удалить производный объект через указатель на него. Стандарт C ++ ясен в этом:

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

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

0
По вопросам рекламы [email protected]