Um die Frage explizit zu beantworten, d.h. wann sollten Sie no einen virtuellen Destruktor deklarieren.
C++ '98/'03
Das Hinzufügen eines virtuellen Destruktors kann dazu führen, dass Ihre Klasse nicht mehr als POD (einfache alte Daten) * oder als Aggregat zu Nicht-POD. Dies kann dazu führen, dass Ihr Projekt nicht mehr kompiliert werden kann, wenn Ihr Klassentyp irgendwo als Aggregat initialisiert ist.
struct A {
// virtual ~A ();
int i;
int j;
};
void foo () {
A a = { 0, 1 }; // Will fail if virtual dtor declared
}
Im Extremfall kann eine solche Änderung auch zu undefiniertem Verhalten führen, wenn die Klasse in einer Weise verwendet wird, die ein POD erfordert, z. B. bei der Übergabe über einen Ellipsis-Parameter oder bei der Verwendung mit memcpy.
void bar (...);
void foo (A & a) {
bar (a); // Undefined behavior if virtual dtor declared
}
[Ein POD-Typ ist ein Typ, der bestimmte Garantien für sein Speicherlayout hat. Der Standard besagt eigentlich nur, dass, wenn man von einem Objekt mit POD-Typ in ein Array von Zeichen (oder Zeichen ohne Vorzeichen) und wieder zurück kopiert, das Ergebnis dasselbe sein wird wie das ursprüngliche Objekt.]
Modernes C++
In neueren Versionen von C++ wurde das Konzept des POD zwischen dem Klassenlayout und dessen Konstruktion, Kopieren und Zerstörung aufgeteilt.
Für den Fall der Ellipse ist es nicht mehr undefiniertes Verhalten, sondern wird nun bedingt unterstützt mit implementierungsdefinierter Semantik (N3937 - ~C++ '14 - 5.2.2/7):
...Die Übergabe eines potentiell bewerteten Arguments vom Typ Klasse (Klausel 9) mit einem nicht-trivialen Kopierkonstruktor, einem nicht-trivialen Verschiebekonstruktor oder einem nicht-trivialen Destruktor ohne entsprechenden Parameter wird mit implementierungsdefinierter Semantik bedingt unterstützt.
Die Deklaration eines anderen Destruktors als =default
wird bedeuten, dass es nicht trivial ist (12.4/5)
... Ein Destruktor ist trivial, wenn er nicht vom Benutzer zur Verfügung gestellt wird ...
Andere Änderungen an Modern C++ verringern die Auswirkungen des Problems der Aggregatinitialisierung, da ein Konstruktor hinzugefügt werden kann:
struct A {
A(int i, int j);
virtual ~A ();
int i;
int j;
};
void foo () {
A a = { 0, 1 }; // OK
}