Quelques heures de retour, je plaisantais avec une question de fuite de mémoire et il s'est avéré que j'ai vraiment eu des trucs de base sur les destructeurs virtuels erronés! Permettez-moi de mettre expliquer ma conception de classe.
class Base { virtual push_elements() {} }; class Derived:public Base { vector<int> x; public: void push_elements(){ for(int i=0;i <5;i++) x.push_back(i); } }; void main() { Base* b = new Derived(); b->push_elements(); delete b; }
8 Réponses :
Si le destructeur n'est pas virtuel, le destructeur de base sera appelé. Le destructeur de base nettoie l'objet de base et se termine. Il n'y a aucun moyen pour le destructeur d'objet de base de savoir sur l'objet dérivé, il doit s'agir du destructeur dérivé appelé, ainsi que la façon de le faire, comme avec n'importe quelle fonction, est de rendre le destructeur virtuel. P>
Ce n'est pas le cas, comme moi et d'autres personnes l'ont souligné, ce que vous obtenez est un comportement indéfini, ce qui ne signifie pas nécessairement que le destructeur de base est appelé.
Appeler le destructeur de base uniquement est la manifestation la plus probable du comportement non défini à être invoqué ici cependant, ce qui est utile de savoir à des fins de débogage.
@Neil: Oui, mais je m'attendrais à ce que le destructeur de base soit appelé la plupart du temps, tout comme je m'attendais à int i = 3; i = i ++ + i ++; code> pour laisser
i code> contenant un petit entiers sans autre changement d'état. C'est important dans ce cas car un comportement plausible conduit aux résultats observés et renforce la probabilité que l'absence d'un destructeur virtuel est ce qui causait le problème. Pensez-y comme plus un problème de diagnostic plutôt qu'un problème de conformité.
@Neil - ce n'est pas comp.lang.c ++. Nous n'avons pas besoin d'ignorer le monde réel afin de faire du pédalage sur ce que dit la norme.
@David Je trouve l'idée de conformité plus utile - s'il avait fourni un destructeur virtuel, il n'aurait plus besoin de diagnostiquer quoi que ce soit.
Suppression d'un objet de classe dérivée via un pointeur de classe de base lorsque la classe de base n'a pas de destruction virtuelle conduit à un comportement indéfini. P>
Qu'est-ce que vous avez observé (que la partie de classe dérivée de l'objet ne soit jamais détruite et que ses membres ne soient jamais distribués) est probablement le plus souvent de nombreux comportements possibles et un bon exemple de la raison pour laquelle il est important de s'assurer Vos destructeurs sont virtuels lorsque vous utilisez le polymorphisme de cette façon. P>
Si la classe de base n'a pas de destructeur virtuel, le résultat de votre code est un comportement indéfini, pas nécessairement le mauvais destructeur appelé. Ceci est vraisemblablement ce que BoundSchecker est diagnostiqué. P>
Les enfants gâtés qui évacuent des réponses techniquement correctes ne constituent pas un spectacle édifiant.
Bien que cela soit techniquement non défini, vous devez toujours connaître la méthode de défaillance la plus courante afin de le diagnostiquer. Cette méthode courante d'échec est d'appeler le mauvais destructeur. Je ne connais aucune mise en œuvre qui échouera d'une autre manière, mais avec certes, je n'utilise que deux implémentations. P>
La raison pour laquelle cela se produit est la même raison que la fonction «mauvaise» sera appelée lorsque vous essayez de remplacer une fonction de membre non virtuelle et de l'appeler via un pointeur de base. P>
de la FAQ C ++ Lite: "Quand mon destructeur devrait-il être virtuel?" Lisez-le ici . (C ++ FAQ Lite est une excellente source pour toutes vos questions relatives à C ++, en passant). P>
Le livre de FAQ C ++ est encore meilleur.
en C ++, un "fort> Destructeur trivial fort> est un concept défini de manière récursive - c'est un destructeur que le compilateur a écrit pour vous lorsque chaque membre de la classe (et chaque classe de base) a un destructeur trivial. (Il y a un concept similaire appelé le constructeur trivial.) P>
Lorsqu'un objet avec un destructeur non trivial est inclus dans un objet (comme le vecteur Donc, même si vous n'avez rien écrit, les réserves d'écriture d'un destructeur non virtuel s'appliquent toujours. P> code> dans votre exemple), puis le destructeur de l'objet extérieur (comme votre
dérivé code>) en n'est plus trivial. Même si vous n'avez pas écrit destructor, le compilateur C ++ a automatiquement écrit un destructeur qui appelle les destructeurs de tous les membres qui ont des destructeurs. P>
Destructor est la fonction de membre de la classe dont le nom est le même nom du nom de la classe et qu'il est précédé par le signe Tilde (~). Le destructeur est utilisé pour détruire l'objet de la classe lorsque l'objet est hors de portée ou vous pouvez dire que tout nettoyage de la destruction de la classe doit être effectué en destructeur. Toute la mémoire est attribuée lors de la construction de l'objet dans la classe se détruit (ou de la libération de la mémoire) lorsque l'objet est hors de portée. P>
Trouver plus de détails avec Exemple sur limitesCheck < / a> p>
Si vous venez de C #, vous aviez raison de vous demander pourquoi le vecteur n'est pas automatiquement désaffecté. Mais en C ++, la gestion automatique de la mémoire n'est pas disponible, sauf si vous utilisez les extexions Microsoft Micote sur C ++ (C ++ / CLI). P>
Étant donné qu'il n'y a pas de destructeur dans la classe de base qui est virtuel, l'objet de classe dérivé ne sera jamais libéré et il fuit là la mémoire allouée pour le membre de données vectoriel de la classe dérivée. P>
S'il vous plaît ne formatez pas votre code à l'aide de HTML. Sélectionnez et appuyez sur la touche
0101 CODE> qui l'indiquera par 4 espaces.
Le code tel que posté n'a pas de relation entre la base et dérivé
@Jrl: merci. Dérivé est dérivé de la base. J'ai fait le changement ..
N'ai-je pas souligné exactement ce que Yacoby vous dit il y a peu de temps? Si vous ignorez de bons conseils, vous trouverez peut-être que les gens ne vont pas répondre à vos questions.