Comme l'auteur de la glisse, je vais essayer de clarifier.
Si vous écrivez du code explicitement l'allocation d'une Derived
exemple avec new
et les détruire avec delete
à l'aide d'une classe de base pointeur ensuite, vous devez définir un virtual
destructeur, sinon vous vous retrouvez avec incomplètement détruire l' Derived
de l'instance. Cependant, je recommande de s'abstenir de l' new
et delete
complètement et utilisez exclusivement shared_ptr
pour la référence à allouées sur la pile polymorphe des objets, comme des
shared_ptr<Base> pb=make_shared<Derived>();
De cette façon, le pointeur partagé garde la trace de l'original destructeur pour être utilisé, même si shared_ptr<Base>
est utilisé pour la représenter. Une fois, la dernière en se référant shared_ptr
est hors de portée ou est remis à zéro, ~Derived()
sera appelée et de la mémoire libérée. Par conséquent, vous n'avez pas besoin de faire d' ~Base()
virtuel.
unique_ptr<Base>
et make_unique<Derived>
ne proposent pas cette fonctionnalité, car ils ne donnent pas la mécanique de l' shared_ptr
à l'égard de la deleter, car pointeur unique est beaucoup plus simple et vise le plus de frais généraux et n'est donc pas le stockage de l'extra pointeur de fonction nécessaires pour la deleter. Avec unique_ptr
le deleter fonction fait partie du type et donc un uniqe_ptr avec un deleter se référant à l' ~Derived
ne serait pas compatible avec un unique_ptr<Base>
utilisent par défaut la deleter, qui serait mauvais pour un dérivé de l'instance de toute façon, si ~Base
n'était pas virtuel.
Les suggestions que je fais, sont destinés à être facile à suivre et suivi tous ensemble. Ils essaient de produire du code plus simple, en permettant à tous de la gestion des ressources être fait par les composants de la bibliothèque et le compilateur de code généré.
La définition d'un (virtuel) destructeur dans une classe, aura pour effet d'interdire à un compilateur fourni déplacer constructeur/opérateur d'affectation et peut interdire également un compilateur fourni constructeur de copie/opérateur d'affectation dans les futures versions de C++. La résurrection est devenue facile avec =default
, mais ressemble encore beaucoup de code réutilisable. Et le meilleur code est le code que vous n'avez pas à écrire, car il ne peut pas être mauvais (je sais qu'il y a toujours des exceptions à cette règle).
Pour résumer "Ne définissent pas un (virtuel) destructeur" qui est le corollaire de mon "la Règle du Zéro":
Lorsque vous créez un polymorphe (OO) la hiérarchie de classes en C++ moderne et voulez/besoin d'allouer ses instances sur le tas et y accéder via une classe de base pointeur utiliser make_shared<Derived>()
de les instancier et d' shared_ptr<Base>
pour les garder autour. Cela vous permet de garder la "Règle du Zéro".
Cela ne signifie pas que vous devez allouer tous les polymorphes objets sur le tas. Par exemple, la définition d'une fonction prenant un (Base&)
comme paramètre, peut être appelée avec un local Derived
variable sans problèmes et se comportera polymorphes, virtuels fonctions de membre de l' Base
.
À mon avis, dynamique OO polymorphisme est fortement utilisées dans de nombreux systèmes. Nous ne devrions pas comme les programmes Java, lorsque nous utilisons C++, sauf si nous avons un problème, où polymorphisme dynamique avec des tas objets alloués est la bonne solution.