Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Destructeur implicite défini explicitement

8 réponses
Avatar
Michel Michaud
Le code suivant compile sans problème avec VC 7.1 :

#include <string>
#include <iostream>

class C
{
std::string s; // Avec rien (ou int) ça ne compile pas

// Aucun destructeur déclaré...
};

C::~C()
{
std::cout << "Hum";
}

int main()
{
C c;
} // Affiche bien Hum, il voit donc le destructeur

C'est clairement un bogue, mais quelqu'un a-t-il une idée
de la logique qui mène à ce bogue ? Surtout qu'en mettant
un int au lieu de std::string, le compilateur se plaint
correctement... J'aimerais bien comprendre s'il n'y a pas
d'autres possibilités de bogues qui seraient reliées et savoir
si d'autres compilateurs tombent dans le panneau !

--
Michel Michaud mm@gdzid.com
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/

8 réponses

Avatar
Mathieu Peyréga
Que se passe-t-il si tu fait :

int main()
{
std::cout << "begin of scope" << std::endl;
{
C c;
}
std::cout << "end of scope" << std::endl;

return 0;
}


Michel Michaud a écrit:
Le code suivant compile sans problème avec VC 7.1 :

#include <string>
#include <iostream>

class C
{
std::string s; // Avec rien (ou int) ça ne compile pas

// Aucun destructeur déclaré...
};

C::~C()
{
std::cout << "Hum";
}

int main()
{
C c;
} // Affiche bien Hum, il voit donc le destructeur

C'est clairement un bogue, mais quelqu'un a-t-il une idée
de la logique qui mène à ce bogue ? Surtout qu'en mettant
un int au lieu de std::string, le compilateur se plaint
correctement... J'aimerais bien comprendre s'il n'y a pas
d'autres possibilités de bogues qui seraient reliées et savoir
si d'autres compilateurs tombent dans le panneau !



Avatar
Michel Michaud
[Message reconstruit dans le bon ordre...]

Dans news:, Mathieu
Michel Michaud a écrit:
Le code suivant compile sans problème avec VC 7.1 :

#include <string>
#include <iostream>

class C
{
std::string s; // Avec rien (ou int) ça ne compile pas

// Aucun destructeur déclaré...
};

C::~C()
{
std::cout << "Hum";
}

int main()
{
C c;
} // Affiche bien Hum, il voit donc le destructeur


Que se passe-t-il si tu fait :

int main()
{
std::cout << "begin of scope" << std::endl;
{
C c;
}
std::cout << "end of scope" << std::endl;

return 0;
}


Ça fait bien ce que c'est supposé faire. Il voit bien le
destructeur, simplement il l'accepte même si on ne l'a
pas déclaré explicitement.

--
Michel Michaud
http://www.gdzid.com
FAQ de fr.comp.lang.c++ :
http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ/


Avatar
Jean-Marc Bourguet
"Michel Michaud" writes:

Le code suivant compile sans problème avec VC 7.1 :

#include <string>
#include <iostream>

class C
{
std::string s; // Avec rien (ou int) ça ne compile pas

// Aucun destructeur déclaré...
};

C::~C()
{
std::cout << "Hum";
}

int main()
{
C c;
} // Affiche bien Hum, il voit donc le destructeur

C'est clairement un bogue, mais quelqu'un a-t-il une idée de la
logique qui mène à ce bogue ? Surtout qu'en mettant un int au lieu
de std::string, le compilateur se plaint correctement... J'aimerais
bien comprendre s'il n'y a pas d'autres possibilités de bogues qui
seraient reliées et savoir si d'autres compilateurs tombent dans le
panneau !


Donner la logique d'un bogue dans un compilateur dont on n'a jamais vu
les sources, ni meme jamais utilise...

Il y a trois cas:
- destructeur implicite sans rien a faire
- destructeur implicite avec quelque chose a faire
- destructeur declare

Apparemment VC 7.1 confonds les deux derniers. Que se passe-t'il si
tu declares le destructeur mais ne le definit pas?

A+

--
Jean-Marc
FAQ de fclc++: http://www.cmla.ens-cachan.fr/~dosreis/C++/FAQ
C++ FAQ Lite en VF: http://www.ifrance.com/jlecomte/c++/c++-faq-lite/index.html
Site de usenet-fr: http://www.usenet-fr.news.eu.org

Avatar
alexis.nikichine
"Michel Michaud" wrote in message news:<XnThc.65979$...
Le code suivant compile sans problème avec VC 7.1 :

#include <string>
#include <iostream>

class C
{
std::string s; // Avec rien (ou int) ça ne compile pas

// Aucun destructeur déclaré...
};

C::~C()
{
std::cout << "Hum";
}

int main()
{
C c;
} // Affiche bien Hum, il voit donc le destructeur

C'est clairement un bogue, mais quelqu'un a-t-il une idée
de la logique qui mène à ce bogue ? Surtout qu'en mettant
un int au lieu de std::string, le compilateur se plaint
correctement... J'aimerais bien comprendre s'il n'y a pas
d'autres possibilités de bogues qui seraient reliées et savoir
si d'autres compilateurs tombent dans le panneau !


Sans être auteur de compilateur, puis-je imaginer le scénario suivant ?

- le compilateur parse la définition de C
- il remarque qu'il y a un objet à destructeur non trivial, contenu
par valeur (std::string), et se dit "damned, je vais devoir génerer un
destructeur non trivial".
- il note donc bien que C a un destructeur non trivial
- puis il tombe sur la définition de C::~C, et il ne bronche pas car
après tout, il sait que C à un destructeur non trivial.

Pour éprouver mes allégations, est-ce que ça marche de la même façon
(euh, est-ce que ca bugge pareil, quoi :-) avec d'autres objets que
std::string, ayant aussi des destructeurs ?

Le panneau que j'imagine est un cas ou le compilateur aurait mélangé les
"symboles" du destructeur des membres par valeur de la classe,
implicitement généré, et le destructeur utilisateur, explicitement
spécifié. Le premier doit-être appelé après le second en principe.

Ici, vu la salade que j'imagine, peux-tu vérifier si le std::string est
effectivement détruit (et sa mémoire pas leakée), ie que ton destructeur
n'a pas complètement remplacé le destructeur implicite ?


Alexis

Avatar
kanze
"Michel Michaud" wrote in message
news:<XnThc.65979$...

Le code suivant compile sans problème avec VC 7.1 :

#include <string>
#include <iostream>

class C
{
std::string s; // Avec rien (ou int) ça ne compile pas

// Aucun destructeur déclaré...
};

C::~C()
{
std::cout << "Hum";
}

int main()
{
C c;
} // Affiche bien Hum, il voit donc le destructeur

C'est clairement un bogue,


Selon quoi ? Moi, aussi, j'ai toujours crû que ça doit être une erreur
(et je crois que c'en était l'intention), mais je ne trouve pas où la
norme le dit. Il y a un destructeur déclaré. Implicitement, mais déclaré
quand même. Tu l'implémentes. Quoi de plus naturel ?

J'ai sans doute raté quelque chose (je ne passe plus des heures à
étudier la norme), mais la seule chose que je vois qui le rendrait
illégal, c'est §12.4/5 : « An implicitly-declared destructor is
implicitly defined when it is used to destroy an objecct of its class
type. » Du coup, il y en a deux définitions, différentes, qui est une
violation de la ODR. Comportement indéfini, alors.

Je suis assez certain que ce n'était pas l'intention de la norme de
permettre à l'utilisateur de définir un destructeur déclaré
implicitement. Est-ce que quelqu'un d'autre trouve où c'est interdit
dans la norme ?

mais quelqu'un a-t-il une idée de la logique qui mène à ce bogue ?


La logique est assez simple. Le destructeur implicit n'est pas trivial.
Internalement, le compilateur distingue probablement entre les classes
qui ont un destructeur non-trivial, et celle dont le destructeur est
trivial ; c'est même probable qu'il utilise la formulation courante qui
dise que la classe n'a pas de destructeur.

Du coup, quand tu cherches à définir le destructeur, le compilateur
régarde si la classe a un destructeur. Elle en a, donc, il accepte la
définition.

Surtout qu'en mettant un int au lieu de std::string, le compilateur se
plaint correctement... J'aimerais bien comprendre s'il n'y a pas
d'autres possibilités de bogues qui seraient reliées et savoir si
d'autres compilateurs tombent dans le panneau !


En ce qui concerne d'autres compilateurs, je n'en sais rien. L'erreur
s'explique assez facilement, à mon avis. Elle pourrait éventuellement
concerner d'autres fonctions déclarées implicitement : le constructeur
de copie, le constructeur par défaut, ou l'opérateur d'affectation.

Aussi, le destructeur implicit est déclaré inline. Ça serait
intéressant de voir si le destructeur que tu as écrit ci-dessus est
considéré inline. (Selon le compilateur, il n'apparaît pas comme global
dans la table des symboles de l'objet, ou tu peux le définir dans
plusieurs unités de compilation sans avoir d'erreur lors de l'édition
des liens.)

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Avatar
Mathieu Peyréga
paragraphe 12 de la norme (enfin la version du doc que j'ai réussi à
récuperer) :

The default constructor (12.1), copy constructor and copy assignment
operator (12.8), and destructor (12.4) are special member functions.
(...)
Program shall not define implicitly-declared member functions.

Et donc ce n'est pas standard... (c'est d'ailleur rejeté par gcc 3.3.3,
je n'ai pas encore eu l'occasion de tester la release 3.4.0...

En revanche, la lecture de la norme (enfin le survol que j'en ai fait
aujourd'hui vu que c'est la première fois que j'avais le doc dans les
mains - version de 1998) Je fait un post pour parler de tout ça dans la
soirée

Cordialement,

Mathieu
Avatar
Mathieu Peyréga
C'est clairement un bogue,


Selon quoi ? Moi, aussi, j'ai toujours crû que ça doit être une erreur
(et je crois que c'en était l'intention), mais je ne trouve pas où la
norme le dit. Il y a un destructeur déclaré. Implicitement, mais déclaré
quand même. Tu l'implémentes. Quoi de plus naturel ?


J'ai l'impression que mon message précédent n'est pas passé...
c'est contraire à la norme (enfin dans le doc que j'ai récupéré qui est une
version qui date de septembre 2003)

Paragraphe 12 : toutes premières lignes :
on y dit que constructeur par défaut, constructeur de copie, operateur
d'assignement et destructeur sont des fonctions membres spéciales.
2 ou 3 lignes plus loins :
Un programme qui ne déclare pas une fonction membre spéciale mais la défini
est "malformé"


Avatar
kanze
Mathieu Peyréga wrote in message
news:<40898583$0$17359$...

C'est clairement un bogue,


Selon quoi ? Moi, aussi, j'ai toujours crû que ça doit être une
erreur (et je crois que c'en était l'intention), mais je ne trouve
pas où la norme le dit. Il y a un destructeur déclaré.
Implicitement, mais déclaré quand même. Tu l'implémentes. Quoi de
plus naturel ?


J'ai l'impression que mon message précédent n'est pas passé... c'est
contraire à la norme (enfin dans le doc que j'ai récupéré qui est une
version qui date de septembre 2003)

Paragraphe 12 : toutes premières lignes :
on y dit que constructeur par défaut, constructeur de copie, operateur
d'assignement et destructeur sont des fonctions membres spéciales.
2 ou 3 lignes plus loins :
Un programme qui ne déclare pas une fonction membre spéciale mais la
défini est "malformé"


Tout à fait. J'avais régardé rapidement toutes les sections sur les
destructeurs, mais je n'avais pas régardé le texte global au début du
chapître.

--
James Kanze GABI Software mailto:
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34