Benoit Rousseau wrote:J'ai lu quelque part dans ces news qu'il fallait déclarer le
destructeur de base comme virtuel ? C'est Bjarne qui a dit ca je
crois dans son bouquin aussi. Dans quelles conditions est-ce vrai ?
(J'ai pas le bouquin et pas l'argent pour l'acheter non plus)
Dès que tu utilises le polymorphisme, il y a de grandes chances que tu
l'utilises via des pointeurs.
Dans ce cas, il est probable que tu effaces l'objet dérivé par un
pointeur sur la classe de base, et c'est le destructeur de la classe
de base qui sera donc appelé à moins que ce dernier n'y soit déclaré
virtuel.
Tu n'as pas le problème si tu "polymorphises" à travers des
références, vu que tu n'as pas véritablement création et destruction
d'objets par ce biais, mais références et pointeurs sont si proches
sémantiquement parlant, que ce serait un peu hasardeux de demander aux
utilisateurs de ta hiérarchie de ne pas utiliser de pointeurs mais que
des références.
Conclusion : dès que tu veux du polymorphisme (notemment dès qu'une
fonction est virtuelle), il faut fournir un destructeur virtuel (même
si on peut toujours imaginer des cas improbables où c'est inutile)...
Benoit Rousseau wrote:
J'ai lu quelque part dans ces news qu'il fallait déclarer le
destructeur de base comme virtuel ? C'est Bjarne qui a dit ca je
crois dans son bouquin aussi. Dans quelles conditions est-ce vrai ?
(J'ai pas le bouquin et pas l'argent pour l'acheter non plus)
Dès que tu utilises le polymorphisme, il y a de grandes chances que tu
l'utilises via des pointeurs.
Dans ce cas, il est probable que tu effaces l'objet dérivé par un
pointeur sur la classe de base, et c'est le destructeur de la classe
de base qui sera donc appelé à moins que ce dernier n'y soit déclaré
virtuel.
Tu n'as pas le problème si tu "polymorphises" à travers des
références, vu que tu n'as pas véritablement création et destruction
d'objets par ce biais, mais références et pointeurs sont si proches
sémantiquement parlant, que ce serait un peu hasardeux de demander aux
utilisateurs de ta hiérarchie de ne pas utiliser de pointeurs mais que
des références.
Conclusion : dès que tu veux du polymorphisme (notemment dès qu'une
fonction est virtuelle), il faut fournir un destructeur virtuel (même
si on peut toujours imaginer des cas improbables où c'est inutile)...
Benoit Rousseau wrote:J'ai lu quelque part dans ces news qu'il fallait déclarer le
destructeur de base comme virtuel ? C'est Bjarne qui a dit ca je
crois dans son bouquin aussi. Dans quelles conditions est-ce vrai ?
(J'ai pas le bouquin et pas l'argent pour l'acheter non plus)
Dès que tu utilises le polymorphisme, il y a de grandes chances que tu
l'utilises via des pointeurs.
Dans ce cas, il est probable que tu effaces l'objet dérivé par un
pointeur sur la classe de base, et c'est le destructeur de la classe
de base qui sera donc appelé à moins que ce dernier n'y soit déclaré
virtuel.
Tu n'as pas le problème si tu "polymorphises" à travers des
références, vu que tu n'as pas véritablement création et destruction
d'objets par ce biais, mais références et pointeurs sont si proches
sémantiquement parlant, que ce serait un peu hasardeux de demander aux
utilisateurs de ta hiérarchie de ne pas utiliser de pointeurs mais que
des références.
Conclusion : dès que tu veux du polymorphisme (notemment dès qu'une
fonction est virtuelle), il faut fournir un destructeur virtuel (même
si on peut toujours imaginer des cas improbables où c'est inutile)...
"Christophe Lephay" schrieb im
Newsbeitrag news:bp2m9p$amd$Benoit Rousseau wrote:
Dès que tu utilises le polymorphisme, il y a de grandes chances que
tu l'utilises via des pointeurs. Dans ce cas, il est probable que tu
effaces l'objet dérivé par un pointeur sur la classe de base, et
c'est le destructeur de la classe de base qui sera donc appelé à
moins que ce dernier n'y soit déclaré virtuel.
Dans la pratique, c'est généralement ce qui se passe (seul le
destructeur de la classe de base est appelé). Mais formellement c'est
un comportement indéfini.
"Christophe Lephay" <christophe-lephay@wanadoo.fr> schrieb im
Newsbeitrag news:bp2m9p$amd$1@news-reader1.wanadoo.fr...
Benoit Rousseau wrote:
Dès que tu utilises le polymorphisme, il y a de grandes chances que
tu l'utilises via des pointeurs. Dans ce cas, il est probable que tu
effaces l'objet dérivé par un pointeur sur la classe de base, et
c'est le destructeur de la classe de base qui sera donc appelé à
moins que ce dernier n'y soit déclaré virtuel.
Dans la pratique, c'est généralement ce qui se passe (seul le
destructeur de la classe de base est appelé). Mais formellement c'est
un comportement indéfini.
"Christophe Lephay" schrieb im
Newsbeitrag news:bp2m9p$amd$Benoit Rousseau wrote:
Dès que tu utilises le polymorphisme, il y a de grandes chances que
tu l'utilises via des pointeurs. Dans ce cas, il est probable que tu
effaces l'objet dérivé par un pointeur sur la classe de base, et
c'est le destructeur de la classe de base qui sera donc appelé à
moins que ce dernier n'y soit déclaré virtuel.
Dans la pratique, c'est généralement ce qui se passe (seul le
destructeur de la classe de base est appelé). Mais formellement c'est
un comportement indéfini.
"Christophe Lephay" wrote in messageDès que tu utilises le polymorphisme, il y a de grandes chances que
tu l'utilises via des pointeurs.
Ou des références. Le polymorphisme ne fonctionne pas autrement.
Dans ce cas, il est probable que tu effaces l'objet dérivé par un
pointeur sur la classe de base, et c'est le destructeur de la classe
de base qui sera donc appelé à moins que ce dernier n'y soit déclaré
virtuel.
Au moins que toutes les instances de la classe (et des classes
dérivées) soient allouées sur la pile, ou statiquement. (Les deux cas
me sont déjà arrivés.) Mais c'est une risque qui ne vaut pas la peine.
Tu n'as pas le problème si tu "polymorphises" à travers des
références, vu que tu n'as pas véritablement création et destruction
d'objets par ce biais, mais références et pointeurs sont si proches
sémantiquement parlant, que ce serait un peu hasardeux de demander
aux utilisateurs de ta hiérarchie de ne pas utiliser de pointeurs
mais que des références.
Que tu utilises des références ou des pointeurs ne changent absolument
rien. Sauf qu'il faut que le paramètre de delete soit un pointeur. Or,
dans l'expression « delete p », si le type dynamique de *p est
différent du type statique, ou bien le type statique a un destructeur
virtuel, ou bien il y a un comportement indéfini.
Conclusion : dès que tu veux du polymorphisme (notemment dès qu'une
fonction est virtuelle), il faut fournir un destructeur virtuel (même
si on peut toujours imaginer des cas improbables où c'est inutile)...
La règle que donne Herb Sutter, c'est ou bien, la classe a un
destructeur virtuel, ou bien elle a un destructeur protégé, ou bien,
tu n'en dérives pas.
Quand tu écris une classe qui ne dérive de rien, une bonne règle de
base, c'est que s'il y a une fonction virtuelle, le destructeur doit
être virtuel.
"Christophe Lephay" <christophe-lephay@wanadoo.fr> wrote in message
Dès que tu utilises le polymorphisme, il y a de grandes chances que
tu l'utilises via des pointeurs.
Ou des références. Le polymorphisme ne fonctionne pas autrement.
Dans ce cas, il est probable que tu effaces l'objet dérivé par un
pointeur sur la classe de base, et c'est le destructeur de la classe
de base qui sera donc appelé à moins que ce dernier n'y soit déclaré
virtuel.
Au moins que toutes les instances de la classe (et des classes
dérivées) soient allouées sur la pile, ou statiquement. (Les deux cas
me sont déjà arrivés.) Mais c'est une risque qui ne vaut pas la peine.
Tu n'as pas le problème si tu "polymorphises" à travers des
références, vu que tu n'as pas véritablement création et destruction
d'objets par ce biais, mais références et pointeurs sont si proches
sémantiquement parlant, que ce serait un peu hasardeux de demander
aux utilisateurs de ta hiérarchie de ne pas utiliser de pointeurs
mais que des références.
Que tu utilises des références ou des pointeurs ne changent absolument
rien. Sauf qu'il faut que le paramètre de delete soit un pointeur. Or,
dans l'expression « delete p », si le type dynamique de *p est
différent du type statique, ou bien le type statique a un destructeur
virtuel, ou bien il y a un comportement indéfini.
Conclusion : dès que tu veux du polymorphisme (notemment dès qu'une
fonction est virtuelle), il faut fournir un destructeur virtuel (même
si on peut toujours imaginer des cas improbables où c'est inutile)...
La règle que donne Herb Sutter, c'est ou bien, la classe a un
destructeur virtuel, ou bien elle a un destructeur protégé, ou bien,
tu n'en dérives pas.
Quand tu écris une classe qui ne dérive de rien, une bonne règle de
base, c'est que s'il y a une fonction virtuelle, le destructeur doit
être virtuel.
"Christophe Lephay" wrote in messageDès que tu utilises le polymorphisme, il y a de grandes chances que
tu l'utilises via des pointeurs.
Ou des références. Le polymorphisme ne fonctionne pas autrement.
Dans ce cas, il est probable que tu effaces l'objet dérivé par un
pointeur sur la classe de base, et c'est le destructeur de la classe
de base qui sera donc appelé à moins que ce dernier n'y soit déclaré
virtuel.
Au moins que toutes les instances de la classe (et des classes
dérivées) soient allouées sur la pile, ou statiquement. (Les deux cas
me sont déjà arrivés.) Mais c'est une risque qui ne vaut pas la peine.
Tu n'as pas le problème si tu "polymorphises" à travers des
références, vu que tu n'as pas véritablement création et destruction
d'objets par ce biais, mais références et pointeurs sont si proches
sémantiquement parlant, que ce serait un peu hasardeux de demander
aux utilisateurs de ta hiérarchie de ne pas utiliser de pointeurs
mais que des références.
Que tu utilises des références ou des pointeurs ne changent absolument
rien. Sauf qu'il faut que le paramètre de delete soit un pointeur. Or,
dans l'expression « delete p », si le type dynamique de *p est
différent du type statique, ou bien le type statique a un destructeur
virtuel, ou bien il y a un comportement indéfini.
Conclusion : dès que tu veux du polymorphisme (notemment dès qu'une
fonction est virtuelle), il faut fournir un destructeur virtuel (même
si on peut toujours imaginer des cas improbables où c'est inutile)...
La règle que donne Herb Sutter, c'est ou bien, la classe a un
destructeur virtuel, ou bien elle a un destructeur protégé, ou bien,
tu n'en dérives pas.
Quand tu écris une classe qui ne dérive de rien, une bonne règle de
base, c'est que s'il y a une fonction virtuelle, le destructeur doit
être virtuel.
Quand tu écris une classe qui ne dérive de rien, une bonne règle de
base, c'est que s'il y a une fonction virtuelle, le destructeur doit
être virtuel.
Quand tu écris une classe qui ne dérive de rien, une bonne règle de
base, c'est que s'il y a une fonction virtuelle, le destructeur doit
être virtuel.
Quand tu écris une classe qui ne dérive de rien, une bonne règle de
base, c'est que s'il y a une fonction virtuelle, le destructeur doit
être virtuel.
Quand tu écris une classe qui ne dérive de rien, une bonne règle
de base, c'est que s'il y a une fonction virtuelle, le destructeur
doit être virtuel.
Et si la classe dérivée n'a rien à detruire de plus que la classe de
base, le destructeur n'a pas besoin d'etre virtuel ?
Quand tu écris une classe qui ne dérive de rien, une bonne règle
de base, c'est que s'il y a une fonction virtuelle, le destructeur
doit être virtuel.
Et si la classe dérivée n'a rien à detruire de plus que la classe de
base, le destructeur n'a pas besoin d'etre virtuel ?
Quand tu écris une classe qui ne dérive de rien, une bonne règle
de base, c'est que s'il y a une fonction virtuelle, le destructeur
doit être virtuel.
Et si la classe dérivée n'a rien à detruire de plus que la classe de
base, le destructeur n'a pas besoin d'etre virtuel ?
Quand tu écris une classe qui ne dérive de rien, une bonne règle de
base, c'est que s'il y a une fonction virtuelle, le destructeur doit
être virtuel.
Et si la classe dérivée n'a rien à detruire de plus que la classe de
base, le destructeur n'a pas besoin d'etre virtuel ?
Quand tu écris une classe qui ne dérive de rien, une bonne règle de
base, c'est que s'il y a une fonction virtuelle, le destructeur doit
être virtuel.
Et si la classe dérivée n'a rien à detruire de plus que la classe de
base, le destructeur n'a pas besoin d'etre virtuel ?
Quand tu écris une classe qui ne dérive de rien, une bonne règle de
base, c'est que s'il y a une fonction virtuelle, le destructeur doit
être virtuel.
Et si la classe dérivée n'a rien à detruire de plus que la classe de
base, le destructeur n'a pas besoin d'etre virtuel ?
"Bertrand Motuelle" wrote in message
news:<bp3h9e$kq6$...Dans la pratique, c'est généralement ce qui se passe (seul le
destructeur de la classe de base est appelé). Mais formellement c'est
un comportement indéfini.
Tu l'as essayé avec combien de compilateurs ? Disons avec le code
suivant :
J'ai une erreur fatale (core dump, échec d'une assertion, etc.) avec
tous les compilateurs que j'ai essayés.
"Bertrand Motuelle" <tib.motuelle@laposte.net> wrote in message
news:<bp3h9e$kq6$1@ulysses.news.tiscali.de>...
Dans la pratique, c'est généralement ce qui se passe (seul le
destructeur de la classe de base est appelé). Mais formellement c'est
un comportement indéfini.
Tu l'as essayé avec combien de compilateurs ? Disons avec le code
suivant :
J'ai une erreur fatale (core dump, échec d'une assertion, etc.) avec
tous les compilateurs que j'ai essayés.
"Bertrand Motuelle" wrote in message
news:<bp3h9e$kq6$...Dans la pratique, c'est généralement ce qui se passe (seul le
destructeur de la classe de base est appelé). Mais formellement c'est
un comportement indéfini.
Tu l'as essayé avec combien de compilateurs ? Disons avec le code
suivant :
J'ai une erreur fatale (core dump, échec d'une assertion, etc.) avec
tous les compilateurs que j'ai essayés.
wrote:"Bertrand Motuelle" wrote in message
news:<bp3h9e$kq6$...Dans la pratique, c'est généralement ce qui se passe (seul le
destructeur de la classe de base est appelé). Mais formellement
c'est un comportement indéfini.
Tu l'as essayé avec combien de compilateurs ? Disons avec le code
suivant :
[snip bout de code avec heritage en losange]J'ai une erreur fatale (core dump, échec d'une assertion, etc.)
avec tous les compilateurs que j'ai essayés.
Je n'ai jamais eu besoin de construire ce genre de hierarchie. Donc je
n'ai jamais essaye un cas tel que tu l'as poste (et de toute facon je
declare le destructeur de la classe virtuel quand je veux documenter
qu'une classe peut servir de classe de base :-)
Je parlais d'heritage simple.
#include <iostream>
#include <ostream>
struct B { ~B() { std::cout << "~B" << std::endl; } };
struct D : B { ~D() { std::cout << "~D" << std::endl; } };
int main()
{
B* b = new D();
delete b;
}
Et la sun CC4.2, CC5.3, CC5.4, g++2.95.? et g++3.2.2 se contentent
d'appeler le destructeur de la classe de base.
Merci pour l'exemple, je vais le conserver precieusement!
kanze@gabi-soft.fr wrote:
"Bertrand Motuelle" <tib.motuelle@laposte.net> wrote in message
news:<bp3h9e$kq6$1@ulysses.news.tiscali.de>...
Dans la pratique, c'est généralement ce qui se passe (seul le
destructeur de la classe de base est appelé). Mais formellement
c'est un comportement indéfini.
Tu l'as essayé avec combien de compilateurs ? Disons avec le code
suivant :
[snip bout de code avec heritage en losange]
J'ai une erreur fatale (core dump, échec d'une assertion, etc.)
avec tous les compilateurs que j'ai essayés.
Je n'ai jamais eu besoin de construire ce genre de hierarchie. Donc je
n'ai jamais essaye un cas tel que tu l'as poste (et de toute facon je
declare le destructeur de la classe virtuel quand je veux documenter
qu'une classe peut servir de classe de base :-)
Je parlais d'heritage simple.
#include <iostream>
#include <ostream>
struct B { ~B() { std::cout << "~B" << std::endl; } };
struct D : B { ~D() { std::cout << "~D" << std::endl; } };
int main()
{
B* b = new D();
delete b;
}
Et la sun CC4.2, CC5.3, CC5.4, g++2.95.? et g++3.2.2 se contentent
d'appeler le destructeur de la classe de base.
Merci pour l'exemple, je vais le conserver precieusement!
wrote:"Bertrand Motuelle" wrote in message
news:<bp3h9e$kq6$...Dans la pratique, c'est généralement ce qui se passe (seul le
destructeur de la classe de base est appelé). Mais formellement
c'est un comportement indéfini.
Tu l'as essayé avec combien de compilateurs ? Disons avec le code
suivant :
[snip bout de code avec heritage en losange]J'ai une erreur fatale (core dump, échec d'une assertion, etc.)
avec tous les compilateurs que j'ai essayés.
Je n'ai jamais eu besoin de construire ce genre de hierarchie. Donc je
n'ai jamais essaye un cas tel que tu l'as poste (et de toute facon je
declare le destructeur de la classe virtuel quand je veux documenter
qu'une classe peut servir de classe de base :-)
Je parlais d'heritage simple.
#include <iostream>
#include <ostream>
struct B { ~B() { std::cout << "~B" << std::endl; } };
struct D : B { ~D() { std::cout << "~D" << std::endl; } };
int main()
{
B* b = new D();
delete b;
}
Et la sun CC4.2, CC5.3, CC5.4, g++2.95.? et g++3.2.2 se contentent
d'appeler le destructeur de la classe de base.
Merci pour l'exemple, je vais le conserver precieusement!
PurL wrote:Quand tu écris une classe qui ne dérive de rien, une bonne règle de
base, c'est que s'il y a une fonction virtuelle, le destructeur
doit être virtuel.
Et si la classe dérivée n'a rien à detruire de plus que la classe de
base, le destructeur n'a pas besoin d'etre virtuel ?
Le problème étant que la classe de base ne peut pas garantir ni
pré-supposer qu'une classe dérivée n'aura jamais rien de plus à
détruire. De toute façon, tu restes dans le comportement indéfini...
PurL wrote:
Quand tu écris une classe qui ne dérive de rien, une bonne règle de
base, c'est que s'il y a une fonction virtuelle, le destructeur
doit être virtuel.
Et si la classe dérivée n'a rien à detruire de plus que la classe de
base, le destructeur n'a pas besoin d'etre virtuel ?
Le problème étant que la classe de base ne peut pas garantir ni
pré-supposer qu'une classe dérivée n'aura jamais rien de plus à
détruire. De toute façon, tu restes dans le comportement indéfini...
PurL wrote:Quand tu écris une classe qui ne dérive de rien, une bonne règle de
base, c'est que s'il y a une fonction virtuelle, le destructeur
doit être virtuel.
Et si la classe dérivée n'a rien à detruire de plus que la classe de
base, le destructeur n'a pas besoin d'etre virtuel ?
Le problème étant que la classe de base ne peut pas garantir ni
pré-supposer qu'une classe dérivée n'aura jamais rien de plus à
détruire. De toute façon, tu restes dans le comportement indéfini...
"Christophe Lephay" wrote in message
news:<bpau00$2qt$...Et si la classe dérivée n'a rien à detruire de plus que la classe de
base, le destructeur n'a pas besoin d'etre virtuel ?
Le problème étant que la classe de base ne peut pas garantir ni
pré-supposer qu'une classe dérivée n'aura jamais rien de plus à
détruire. De toute façon, tu restes dans le comportement indéfini...
Le problème, et c'est ce qu'on s'entête à dire, n'a rien à voir avec
l'appel ou non du destructeur de la classe dérivée. C'est un
comportement indéfini, et c'est un comportement indéfini qui ne marche
réelement pas dans bien de cas. Le problème, c'est que sur des petits
exemples, on ne voit pas forcement qu'on a bousillé le tas, et qu'une
allocation on ne sait pas trop quand dans l'avenir va foirer, ou
qu'il y a une fuite de mémoire, ou que sais-je.
Toute explication qui se base sur ce qui se fait, ou sur ce qui
pourrait se faire, dans le destructeur de la classe dérivée, est
radicalement incomplète.
"Christophe Lephay" <christophe-lephay@wanadoo.fr> wrote in message
news:<bpau00$2qt$1@news-reader5.wanadoo.fr>...
Et si la classe dérivée n'a rien à detruire de plus que la classe de
base, le destructeur n'a pas besoin d'etre virtuel ?
Le problème étant que la classe de base ne peut pas garantir ni
pré-supposer qu'une classe dérivée n'aura jamais rien de plus à
détruire. De toute façon, tu restes dans le comportement indéfini...
Le problème, et c'est ce qu'on s'entête à dire, n'a rien à voir avec
l'appel ou non du destructeur de la classe dérivée. C'est un
comportement indéfini, et c'est un comportement indéfini qui ne marche
réelement pas dans bien de cas. Le problème, c'est que sur des petits
exemples, on ne voit pas forcement qu'on a bousillé le tas, et qu'une
allocation on ne sait pas trop quand dans l'avenir va foirer, ou
qu'il y a une fuite de mémoire, ou que sais-je.
Toute explication qui se base sur ce qui se fait, ou sur ce qui
pourrait se faire, dans le destructeur de la classe dérivée, est
radicalement incomplète.
"Christophe Lephay" wrote in message
news:<bpau00$2qt$...Et si la classe dérivée n'a rien à detruire de plus que la classe de
base, le destructeur n'a pas besoin d'etre virtuel ?
Le problème étant que la classe de base ne peut pas garantir ni
pré-supposer qu'une classe dérivée n'aura jamais rien de plus à
détruire. De toute façon, tu restes dans le comportement indéfini...
Le problème, et c'est ce qu'on s'entête à dire, n'a rien à voir avec
l'appel ou non du destructeur de la classe dérivée. C'est un
comportement indéfini, et c'est un comportement indéfini qui ne marche
réelement pas dans bien de cas. Le problème, c'est que sur des petits
exemples, on ne voit pas forcement qu'on a bousillé le tas, et qu'une
allocation on ne sait pas trop quand dans l'avenir va foirer, ou
qu'il y a une fuite de mémoire, ou que sais-je.
Toute explication qui se base sur ce qui se fait, ou sur ce qui
pourrait se faire, dans le destructeur de la classe dérivée, est
radicalement incomplète.