TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.35K subscribers
Post #269 3.85K
​Виртуальный деструктор

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

Объект каждого класса обладает своим жизненным циклом: начало, счастливая жизнь и конец. С началом ассоциирован - конструктор, а с концом - деструктор, о котором и пойдет речь дальше. Он вызывается автоматически, когда объект удаляется вручную или автоматически. Это даёт возможность корректно завершить работу, которую выполнял объект. Например, освободить выделенную в конструкторе память, закрыть сокет. Это позволяет поддерживать систему в валидном состоянии на протяжении всей работы программы. Это счастливый конец!

Условно, если вы поработали в мастерской, значит, уходя из неё, надо всё за собой убрать и разложить по полочкам. Иначе следующий мастер там просто не найдет нужный инструмент, запнется о мусор и еще что-нибудь испортит. Повторим это с десяток раз и можно сжигать мастерскую 😃. Кажется, что сжигать мастерскую — это перебор 🤭, но именно так и поступит система: прибьет её из-за исчерпания памяти (Out Of Memory). Это грустный конец...

Вернёмся к динамическому полиморфизму. Давайте свяжем два наблюдения:
1) Зачастую, наследники полиморфных классов могут владеть ресурсом, который обязаны вернуть системе (например, память на куче).
2) Зачастую, взаимодействие происходит через указатель на родительский класс.

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

Из этого следует, что корректное удаление объекта подразумевает вызов деструктора класса наследника. И вот как его вызвать, если тип указателя - родительский? Например тут:
Parent *data = new Child();
...
delete data;

Пишу тут new и delete в ознакомительных целях. Используйте умные указатели: unique_ptr, shared_ptr.

Есть простое встроенное решение 😊 Отмечайте деструктор родительского класса виртуальным! Пример:
struct Parent
{
...
   virtual ~Parent() {...}
   ...
};

Вызов виртуального деструктора приведёт к вызову цепочки деструкторов у всех наследников от родительского до динамического типа:
... -> ~Child_2() -> ~Child_1() -> ~Parent();

Если в иерархии классов деструктор не был отмечен виртуальным, то будет вызван только деструктор класса, который является типом указателя. Деструктор наследника не будет вызван вообще, следовательно, ресурс будет упущен. Добавлю живой пример, в котором количество выделяемых ресурсов не совпадает с освобождаемым. Как-нибудь напишем, как это дело проверять по-нормальному 😉

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

Есть еще один тонкий момент. Кажется, что если полиморфное семейство не выделяет никаких ресурсов, то и проблем не будет. Но это пока! Пройдет время, код эволюционирует, появятся такие ресурсы и вот тогда что-то может да потечь. Короче, это чеховское ружьё 😉

Помочь избежать этих проблем поможет, как всегда, предупреждение:
-Wdelete-non-virtual-dtor

#cppcore
  • 👍 27
  • ❤‍🔥 7
  • 🙏 5
  • 🥰 2
  • 🤔 2
  • ❤ 1
More from @grokaemcpp
  1. Oct 14, 2026​​Что внутри std::condition_variable? #опытным Более менее все знакомы с примитивом синхро…
  2. Oct 12, 2026​​WAT #новичкам Как вы думаете, результат выражения: bool math = -1 < 1U; будет правдой ил…
  3. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  4. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  5. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  6. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →