Чтобы ответить на вопрос явно, то есть когда не объявляйте виртуальный деструктор.
C ++ '98 / '03
Добавление виртуального деструктора может изменить ваш класс с POD (обычные старые данные) * или агрегировать на не POD. Это может остановить ваш проект от компиляции, если ваш тип класса где-то инициализирован агрегатом.
struct A {
// virtual ~A ();
int i;
int j;
};
void foo () {
A a = { 0, 1 }; // Will fail if virtual dtor declared
}
В крайнем случае такое изменение может также привести к неопределенному поведению, когда класс используется таким образом, который требует POD, например, передавая его через параметр с многоточием или используя его с memcpy.
void bar (...);
void foo (A & a) {
bar (a); // Undefined behavior if virtual dtor declared
}
[* Тип POD - это тип, который имеет определенные гарантии для своей структуры памяти. В действительности стандарт действительно говорит только о том, что если вы скопируете объект с типом POD в массив символов (или символов без знака) и обратно, то результат будет таким же, как и у исходного объекта.]
Современный C ++
В последних версиях C ++ концепция POD была разделена между макетом класса и его конструированием, копированием и уничтожением.
Для случая с многоточием это больше не неопределенное поведение, теперь оно условно поддерживается с помощью семантики, определенной реализацией (N3937 - ~ C ++ '14 - 5.2.2 / 7):
... Передача потенциально оцениваемого аргумента типа класса (раздел 9), имеющего нетривиальный конструктор копирования, нетривиальный конструктор перемещения или тривиальный деструктор без соответствующего параметра, условно поддерживается с определенной реализацией семантикой.
Объявление деструктора, отличного от =default
, будет означать, что он не тривиален (12.4 / 5)
... Деструктор тривиален, если он не предоставляется пользователем ...
Другие изменения в Modern C ++ уменьшают влияние проблемы инициализации агрегата, так как конструктор может быть добавлен:
struct A {
A(int i, int j);
virtual ~A ();
int i;
int j;
};
void foo () {
A a = { 0, 1 }; // OK
}