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

Polymorphisme, sémantique de valeur, durée de vie des temporaires...

38 réponses
Avatar
Marc Boyer
Bonjour,

j'ai un problème 'pure virtual method called' (avec g++), et je n'arrive
pas à faire d'exemple minimal qui reproduise le pb...

Mais j'ai peut etre identifié le pb. Quand j'écris un truc du genre
X x( Y(1) );
avec X et Y deux classes, quelle est la durée de vie de l'objet
temporaire Y ?

Actuellement, je prends une référence sur cet objet, et visiblement
il aime pas. Alors que si j'écris
X x( *(new Y(1)) );
ça marche bien.

Merci,

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)

10 réponses

1 2 3 4
Avatar
Sylvain
Marc Boyer wrote on 07/03/2007 13:42:

Alors je pourrais sortir l'artillerie des pointeurs, ou de methode
..clone(), mais j'ai la flemme. C'est du code jetable.


tu peux garder une sémantique référence (et non pointeurs) mais ajouter
en effet un clone et des destructeurs propres.

Sylvain.


struct Fonction {
virtual ~Fonction(){}
virtual Fonction& clone() const = 0;
virtual double operator()(double x) const = 0;
};

class Affine : public Fonction {
double a;
public:
Affine(double _a) : a(_a){}
Fonction& clone() const {
return *new Affine(a);
}
double operator()(double x) const {
return a*x;
}
};

class Min : public Fonction {
Fonction& f;
Fonction& g;
public:
Min(const Fonction& _f, const Fonction& _g) :
f(_f.clone()), g(_g.clone()){
}
~Min(){
delete &f;
delete &g;
}
Fonction& clone() const {
return *new Min(f, g);
}
double operator()(double x) const {
return min( f(x), g(x) );
}
};

int main(){
Min m( Affine(2), Affine(3) );
assert(m(1)== 2);
Min m2( Min(Affine(2), Affine(3)), Affine(4) );
assert( m(1)== 2 );
return 0;
}

Avatar
Jean-Marc Bourguet
Marc Boyer writes:

Le 07-03-2007, Jean-Marc Bourguet a écrit :
Marc Boyer writes:

Si le véritable exemple t'intéresse, je peux te le poster.
Ca n'est pas très long (7 classes, 400 lignes, 10ko de code).


Tu peux le faire ou me l'envoyer en perso. Je ne garanti pas de reponse
rapide.


Levons une ambiguïté: en ce qui me concerne, l'explication sur
la gestion des temporaires me convient, en j'ai une solution à
base de *(new X(1)), qui crée des objets persistants.
Après, Laurent était étonné par la nature du message d'erreur et
je lui proposais le code s'il le voulait. Cela vaut aussi pour
toi.
Mais ne fait pas ça pour moi, mais uniquement pour satisfaire ta
curiosité.


J'aimerais bien comprendre pourquoi ton exemple reduit ne donne pas le
message que tu as avec le code complet... Et ce avec au moins 2
compilateurs d'origine differentes meme en non optimise, donc il y a peut
de chance que ce soit un artefact d'un compilateur qui applique une
optimisation tenant compte du fait que tout est visible.

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
Marc Boyer
Le 07-03-2007, Sylvain a écrit :
Marc Boyer wrote on 07/03/2007 13:42:

Alors je pourrais sortir l'artillerie des pointeurs, ou de methode
..clone(), mais j'ai la flemme. C'est du code jetable.


tu peux garder une sémantique référence (et non pointeurs) mais ajouter
en effet un clone et des destructeurs propres.


C'est ce qu'il me semblait.

struct Fonction {
virtual ~Fonction(){}
virtual Fonction& clone() const = 0;
virtual double operator()(double x) const = 0;
};

class Affine : public Fonction {
double a;
public:
Affine(double _a) : a(_a){}
Fonction& clone() const {
return *new Affine(a);


Là, j'aurais carrément fait un appel au constructeur de copie
implicite. Comme ça, le jour où je fais des courbes ax+b, j'ai
pas à modifier le code.

return *new Affine(*this);
}
double operator()(double x) const {
return a*x;
}
};

class Min : public Fonction {
Fonction& f;
Fonction& g;
public:
Min(const Fonction& _f, const Fonction& _g) :
f(_f.clone()), g(_g.clone()){
}
~Min(){
delete &f;
delete &g;
}


Oui.

Fonction& clone() const {
return *new Min(f, g);
}


Oui, et on fait une copie profonde (deep_copie). En fait,
comme tout est const, avec des shared_ptr, on doit même
pouvoir éviter la copie profonde. Mais bon...

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)


Avatar
Sylvain
Marc Boyer wrote on 07/03/2007 15:32:

le polymorphisme existe toujours mais en effet 'Fonction' est virtuel pure.


Le polymorphisme existe toujours ? Tu peux développer ?


le "polymorphisme" telle une notion générique non.
le comportement polymorphe de tes instances, oui.

f et g sont des instances d'une classe ayant des méthodes virtuelles, en
particulier l'opérateur (), l'appel à f(double) et g(double) se fait
donc par une résolution virtuelle (polymorphe) de cette méthode (un
virtual_invoke et non static_invoke puisque tu trouves Java cohérent -
ce qui te sauverait pour ce code en Java tient plus de son ref. counting
que d'un problème de cohérence d'ailleurs).

il se trouve que lorsque Min () utilise f()et g(), f et g sont réduit à
des Fonction, leur résolution polymorphe tourne alors court à la seule
évaluation de Fonction::()

des données membre pointeurs sont pourtant la bonne solution, [...]
Oui, si ce code avait vocation à durer, je ferais ça.



s'il a vocation à ne pas durer mais aussi à ne pas fonctionner même une
seule fois, tu peux en effet t'en passer.

Sylvain.


Avatar
Sylvain
Sylvain wrote on 07/03/2007 15:57:

f et g sont des instances d'une classe ayant [...]


lire: f et g sont des références à une classe ...
(j'écris trop aujourd'hui!)

Sylvain.

Avatar
Marc Boyer
Le 07-03-2007, Sylvain a écrit :
Marc Boyer wrote on 07/03/2007 15:32:
le polymorphisme existe toujours mais en effet 'Fonction' est virtuel pure.


Le polymorphisme existe toujours ? Tu peux développer ?


le "polymorphisme" telle une notion générique non.
le comportement polymorphe de tes instances, oui.

f et g sont des instances d'une classe ayant des méthodes virtuelles, en
particulier l'opérateur (), l'appel à f(double) et g(double) se fait
donc par une résolution virtuelle (polymorphe) de cette méthode (un
virtual_invoke et non static_invoke puisque tu trouves Java cohérent -
ce qui te sauverait pour ce code en Java tient plus de son ref. counting
que d'un problème de cohérence d'ailleurs).

il se trouve que lorsque Min () utilise f()et g(), f et g sont réduit à
des Fonction, leur résolution polymorphe tourne alors court à la seule
évaluation de Fonction::()


OUi, mais c'est toujours Fonction::() qui est appelé.

des données membre pointeurs sont pourtant la bonne solution, [...]
Oui, si ce code avait vocation à durer, je ferais ça.



s'il a vocation à ne pas durer mais aussi à ne pas fonctionner même une
seule fois, tu peux en effet t'en passer.


Mais il marche très bien actuellement ;-)
Il est laid, mais il marche.

Marc Boyer
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)



Avatar
Marc Boyer
Le 07-03-2007, Jean-Marc Bourguet a écrit :
Marc Boyer writes:

Le 07-03-2007, Jean-Marc Bourguet a écrit :
Marc Boyer writes:

Si le véritable exemple t'intéresse, je peux te le poster.
Ca n'est pas très long (7 classes, 400 lignes, 10ko de code).


Tu peux le faire ou me l'envoyer en perso. Je ne garanti pas de reponse
rapide.


Levons une ambiguïté: en ce qui me concerne, l'explication sur
la gestion des temporaires me convient, en j'ai une solution à
base de *(new X(1)), qui crée des objets persistants.
Après, Laurent était étonné par la nature du message d'erreur et
je lui proposais le code s'il le voulait. Cela vaut aussi pour
toi.
Mais ne fait pas ça pour moi, mais uniquement pour satisfaire ta
curiosité.


J'aimerais bien comprendre pourquoi ton exemple reduit ne donne pas le
message que tu as avec le code complet... Et ce avec au moins 2
compilateurs d'origine differentes meme en non optimise, donc il y a peut
de chance que ce soit un artefact d'un compilateur qui applique une
optimisation tenant compte du fait que tout est visible.


Bon, je n'arrive plus à avoir les deux comportements différents :-(
Ca plante dans tous les cas. C'est plutot normal.
Désolé de vous avoir fait perdre du temps. J'ai du m'emmeller
dans les versions.

Marc
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)




Avatar
Laurent Deniau
Marc Boyer wrote:
Marc Boyer wrote:
class Min : public Fonction {
const Fonction& f;
const Fonction& g;
Probleme ici. Il ne faut pas utiliser des references mais des copies.

Avec des copies

const Fonction f;
je perds le polymorphisme (et sur ce coup, il se plaint que Fonction
a une méthode virtuelle pure).
ok, j'avais rate ce details.



Oui. En je pensais que tu me ferais un couplet sur le choix
inadéquat de C++ de privilégier la sémantique de valeur.


Plus la peine, tu le fait tout seul ;-) Ceci dit, je n'ai pas dis que
c'etait inadequat, j'ai dit que c'etait (beaucoup) plus complique. Mais
c'est obligatoire quand on fait le choix de 1) rester compatible avec le
C, 2) etre tres efficace et 3) conserver un modele proche de celui de la
machine.

Je réalise que quand on veut le polymorphisme, on est
obligé de ce taper pleins de pointeurs,


condition incontournable pour avoir le polymorphisme d'inclusion.

et qu'en fait,
Java est cohérent sur ce point.


Mouais, il a un GC quoi. Je trouve Objective-C est plus coherent sur ce
point.

Non, pas vraiment. Je sais comment produire facilement des 'pure virtual
call' tout seul comme un grand ;-) Et en plus je suis a la bourre pour
mon papier OOPSLA (date de cloture le 19 mars, sic!) donc d'ici la...


Il te reste 12 jours. Ca dépend s'il faut encore obtenir les
résultats ou juste mettre en forme le papier...


J'ai les resultats mais il me reste a les mettre en ordre et j'ai ecrit
seulement 25% du papier pour l'instant (en 4 jours). Le probleme, c'est
qu'il y a beaucoup de chose a dire et que 10000 mots c'est pas beaucoup
alors au debut je reflechissais murement a ce que j'allais dire (je
comptais meme les mots). Maintenant j'ecris les lignes au kilometre et
j'effacerais / reformulerais a la fin en fonction du surplus (ce qui
suppose que je finisse en avance sic!).

a+, ld.





Avatar
Marc Boyer
Le 07-03-2007, Laurent Deniau a écrit :
Marc Boyer wrote:
Marc Boyer wrote:
class Min : public Fonction {
const Fonction& f;
const Fonction& g;
Probleme ici. Il ne faut pas utiliser des references mais des copies.

Avec des copies

const Fonction f;
je perds le polymorphisme (et sur ce coup, il se plaint que Fonction
a une méthode virtuelle pure).
ok, j'avais rate ce details.



Oui. En je pensais que tu me ferais un couplet sur le choix
inadéquat de C++ de privilégier la sémantique de valeur.


Plus la peine, tu le fait tout seul ;-) Ceci dit, je n'ai pas dis que
c'etait inadequat, j'ai dit que c'etait (beaucoup) plus complique. Mais
c'est obligatoire quand on fait le choix de 1) rester compatible avec le
C, 2) etre tres efficace et 3) conserver un modele proche de celui de la
machine.


Oui.

Je réalise que quand on veut le polymorphisme, on est
obligé de ce taper pleins de pointeurs,


condition incontournable pour avoir le polymorphisme d'inclusion.


Et oui. Je le savais en théorie. Là, dans la pratique, je
l'expérimente.

Non, pas vraiment. Je sais comment produire facilement des 'pure virtual
call' tout seul comme un grand ;-) Et en plus je suis a la bourre pour
mon papier OOPSLA (date de cloture le 19 mars, sic!) donc d'ici la...


Il te reste 12 jours. Ca dépend s'il faut encore obtenir les
résultats ou juste mettre en forme le papier...


J'ai les resultats mais il me reste a les mettre en ordre et j'ai ecrit
seulement 25% du papier pour l'instant (en 4 jours). Le probleme, c'est
qu'il y a beaucoup de chose a dire et que 10000 mots c'est pas beaucoup
alors au debut je reflechissais murement a ce que j'allais dire (je
comptais meme les mots).


mon dieu...

Maintenant j'ecris les lignes au kilometre et
j'effacerais / reformulerais a la fin en fonction du surplus (ce qui
suppose que je finisse en avance sic!).


Aller, j'arrête de te prendre du temps et je te souhaite une bonne
inspiration.


Marc
--
Si tu peux supporter d'entendre tes paroles
Travesties par des gueux pour exciter des sots
IF -- Rudyard Kipling (Trad. André Maurois)






Avatar
James Kanze
On Mar 7, 10:33 am, Jean-Marc Bourguet wrote:
Marc Boyer writes:
j'ai un problème 'pure virtual method called' (avec g++), et je n'arr ive
pas à faire d'exemple minimal qui reproduise le pb...


Generalement ca arrive quand on appelle un membre virtuel dans le
constructeur ou le destructeur d'un objet.


Généralement, oui. J'ai comme une petite doute que Marc se
trouve dans un cas particulier.

Mais j'ai peut etre identifié le pb. Quand j'écris un truc du genre
X x( Y(1) );
avec X et Y deux classes, quelle est la durée de vie de l'objet
temporaire Y ?


Comme tous les temporaires qui ne sont pas bindé a une
variable reference: jusqu'a la fin de l'expression.


Généralement, oui. Ici, Marc se trouve bien dans un cas
particulier, et le temporaire reste en vie jusqu'au rétour du
constructeur d'x (constructeur qui ne fait pas partie de
l'expression).

Actuellement, je prends une référence sur cet objet,


Si tu la conserve au dela du constructeur de x (comme le
laisse croire la suite), c'est fort possible que ce soit la
source de ton probleme (et on ne se retrouve pas dans le cas
general mais vraissemblablement tu appelles le membre virtuel
apres la fin de l'execution du destructeur de Y(1)).


C'est ce dont je me doute aussi. S'il essaie d'utiliser l'objet
après avoir sortie du constructeur, c'est un comportement
indéfini. Et évidemment, alors, tout est possible. D'après ce
que je connais de g++, si la mémoire où se trouvait l'objet n'a
pas encore reservi, s'il appelle une fonction virtuelle de
l'objet, il aurait exactement le même comportement que s'il
l'avait appelée dans le destructeur de la classe de base (sauf
que les variables membres de la classe de base auront été
détruites).

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


1 2 3 4