Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
1542 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  Design pour eviter un virtual...

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Design pour eviter un virtual...

n°1437918
zboub77
Posté le 06-09-2006 à 18:51:54  profilanswer
 

Bonjour à tous,
 
J'ai un problème de design que je n'arrive pas à résoudre comme j'aimerais... Ceci se pose dans le cadre de recherche de performance pour des programmes à caractère scientifique.
Considerons les classes A et B héritées de Base, par exemple, en oubliant les constructeurs & co :

Code :
  1. class Base {
  2. public:
  3.    virtual void do() = 0;
  4. };
  5. class A : public Base {
  6. public:
  7.    void do() { /* do par A */ }
  8. };
  9. class B : public Base {
  10. public:
  11.    void do() { /* do par B */ }
  12. };


Je peux donc écrire

Code :
  1. /* ... code ... */
  2. Base * base;
  3. /* ... code avec test et pis ... */
  4. base = new A; /* ou  base = new A; si je veux */
  5. base.do();


Ok mais on sait que la notion virtual handicape énormément en terme de performance si le do() a lieu dans un boucle par exemple. L'heritage doit rester haut niveau...  
Auriez vous des idées pour garder une écriture générique tout en assurant des perfs pour un cas comme celui ci? Par exemple dans l'esprit des techniques curiously template?  
 
Merci d'avance

mood
Publicité
Posté le 06-09-2006 à 18:51:54  profilanswer
 

n°1437936
el muchach​o
Comfortably Numb
Posté le 06-09-2006 à 19:40:34  profilanswer
 

Il y a souvent des moyens d'éviter de dériver, qui est le moyen le moins souple d'ajouter des fonctionnalités à une classe.
La dérivation n'a réellement d'intérêt que si la relation "est un" est vérifiée et on n'est sûr que la hiérarchie de classes n'a aucun risque d'exploser combinatoirement.
 
Sinon, on peut utiliser la composition (pointeurs sur objets en tant que membres de classes), le pattern decorator pour rajouter des fonctionnalités, ou ajouter des propriétés grâce à une bibliothèque de mixins. Cette dernière méthode peut être élégante et performante si bien utilisée. (google est ton ami)


Message édité par el muchacho le 06-09-2006 à 19:47:42

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
n°1437939
Joel F
Real men use unique_ptr
Posté le 06-09-2006 à 20:00:42  profilanswer
 

ou faire de l'heritage statique avec des templates

n°1438002
zboub77
Posté le 07-09-2006 à 00:08:35  profilanswer
 

Merci de ces pistes!! j'enquète... :)

n°1438114
franceso
Posté le 07-09-2006 à 10:33:49  profilanswer
 

Joel F a écrit :

ou faire de l'heritage statique avec des templates


+1


---------------
TriScale innov
n°1438787
zboub77
Posté le 08-09-2006 à 02:03:34  profilanswer
 

N'auriez vous pas un exemple simple d'heritage statique avec template?
Merci d'avance!

n°1439082
Joel F
Real men use unique_ptr
Posté le 08-09-2006 à 14:08:44  profilanswer
 

Code :
  1. template< class D >
  2. class Base
  3. {
  4.   public :
  5.   void someMethod();
  6. };
  7. class SomeDerived : public Base<SomeDerived>
  8. {
  9.   public:
  10.   typedef  Base<SomeDerived> base_t;
  11.   SomeDerived() : base_t() {}
  12.   void someMethod()
  13.   {
  14.      base_t::soemMethod();
  15.     // Derived code if needed
  16.   }
  17. };
  18. SoemDerived a;
  19. a.someMethod();


 

Message cité 1 fois
Message édité par Joel F le 08-09-2006 à 14:09:48
n°1439142
Taz
bisounours-codeur
Posté le 08-09-2006 à 15:21:02  profilanswer
 


t'auras beau essayé, s'il faut de la résolution dynamique, ben il la faut. C'est incompatible avec l'usage souhaité.
 
Quant à l'affirmation 'on sait que c'est lent' c'est typique de l'optimisation prématurée basée sur un mythe.


Message édité par Taz le 08-09-2006 à 15:21:20
n°1439143
skelter
Posté le 08-09-2006 à 15:22:09  profilanswer
 

j'ai 2 questions:
quel est le sens de "heritage statique" ?  pour moi c'a na aucun sens, l'heritage est un schema de structure qui est resolu a la compilation
a quoi sert ce modele ?
 
et puis ca ne reponds pas a la question qui est comment ecrire ce genre de code

Code :
  1. /* ... code ... */
  2. Base * base;
  3. /* ... code avec test et pis ... */
  4. base = new A; /* ou  base = new A; si je veux */
  5. base.do();


sans l'inconvenient du cout d'un appel de methode virtuelle (mais qui est franchement negligeable pour peu que la methode fasse autre chose que 1+1, sortez vos profiler) et a ce probleme il n'y a pas de solution.

n°1439144
skelter
Posté le 08-09-2006 à 15:24:26  profilanswer
 


 
c'est quoi "l'heritage statique" ?

mood
Publicité
Posté le 08-09-2006 à 15:24:26  profilanswer
 

n°1439164
_darkalt3_
Proctopathe
Posté le 08-09-2006 à 15:41:02  profilanswer
 

skelter a écrit :

c'est quoi "l'heritage statique" ?


+1


---------------
Töp of the plöp
n°1439174
franceso
Posté le 08-09-2006 à 15:47:15  profilanswer
 

skelter a écrit :

c'est quoi "l'heritage statique" ?

Je pense qu'il vaut mieux parler de polymorphisme statique, plutôt que d'héritage statique.
 
Pour moi le polymorphisme statique est la possibilité pour une classe d'hériter du comportement d'une autre classe, sans pour autant perdre en performance, puisque tout se résout à la compilation grâce aux mécanismes de templates, plutôt qu'à l'exécution avec des vtables.
 
Cela dit, je suis d'accord avec Taz: cela ne remplace pas le dynamique s'il y en a vraiment besoin. Par contre il y a de nombreux cas où on use de l'héritage et du polymorphisme dynamique uniquement pour des besoins de design ; dans certains de ces cas, il pourrait être avantageux d'utiliser des templates.
 
La perte d'efficacité dues aux vtables n'est pas un mythe. Il suffit de faire quelques tests pour voir qu'un appel de fonction virtuelle coûte à peu près 5x plus cher qu'un appel normal. Donc il y a des cas dans lesquels il est utile de se passer des fonctions virtuelles. (il faudrait en savoir un peu plus sur le problème de zboub77 pour savoir si c'est le cas ici)


---------------
TriScale innov
n°1439249
Taz
bisounours-codeur
Posté le 08-09-2006 à 17:38:51  profilanswer
 

... c'est n'importe quoi ...
 
   1.
      /* ... code ... */
   2.
      Base * base;
   3.
      /* ... code avec test et pis ... */
   4.
      base = new A; /* ou  base = new A; si je veux */
   5.
      base.do();  
 
 
(je passe sur le do)
 
OK, un bon compilateur peut faire sans vtable là, mais étant donné un base*, le cas général, il doit passer par la vtable. S'il n'y a pas de résolution, bah il n'y a pas de surcharge possible. Je vois juste de l'enculage de mouche. Si tu mets pas virtual, ça résout rien, ça surcharge rien. "L'héritage statique" c'est de l'héritage sans virtual. Dans un contexte polymorphique ça ne marche pas. Circulez y a rien à voir.

n°1439557
zboub77
Posté le 09-09-2006 à 18:11:30  profilanswer
 

yep, donc rien que je n'aurais pas vu...
 
En particuiler, la méthode "polymorphisme statique" ou "heritage statique" est appelée "Curiously Recursive Pattern". Comme dit Skelter, j'utilise ca pour faire quasiment un "1+1" dans le do()... et un très grand nombre de fois....

n°1439558
zboub77
Posté le 09-09-2006 à 18:12:52  profilanswer
 

Vivement le mot clé "auto" dans la prochaine norme!! il y aura alors des astuces pour s'affranchir de ces problèmes! :)
 
En tous cas, merci!

n°1439592
franceso
Posté le 09-09-2006 à 23:27:44  profilanswer
 

Taz a écrit :

... c'est n'importe quoi ...

Qu'est-ce qui est n'importe quoi ?
T'es pas d'accord avec ce que j'ai dit :??:


---------------
TriScale innov
n°1439606
slash33
Posté le 10-09-2006 à 00:51:31  profilanswer
 

Bon alors le polymorphisme dynamique (comprenez le bon vieux virtual) c'est le mal ou non ?

n°1439627
nargy
Posté le 10-09-2006 à 07:40:17  profilanswer
 

Citation :


Bon alors le polymorphisme dynamique (comprenez le bon vieux virtual) c'est le mal ou non ?


Non
J'avais posté il y a quelque temps un code de classe Polymère (c'était une blague) qui illustre le fonctionnement des vtables:

Code :
  1. #include <iostream>
  2. // classe polymère parente
  3. class Objet
  4. {
  5.   const char* monnom;
  6.   virtual void maClasse() { cout<<"Objet"<<endl; }
  7.   protected:
  8.   Objet& operator=(const Objet& o)
  9.   { *((char**)this)=*((char**)&o); return *this; }
  10.   public:
  11.   Objet(const char* nom): monnom(nom) {}
  12.   void quiSuisJe() { cout<<"Mon nom est "<<monnom<<", je suis un "; maClasse(); }
  13. };
  14. // deux classes polymères filles
  15. class ObjetA; class ObjetB;
  16. // classe polymère A
  17. class ObjetA: public Objet
  18. {
  19.   void maClasse() { cout<<"ObjetA"<<endl; }
  20.   public:
  21.   ObjetA(const char* nom): Objet(nom) {}
  22.   ObjetA& operator=(const ObjetB& b)
  23.   { Objet::operator=((Objet& )b); return *this; }
  24. };
  25. // classe polymère B
  26. class ObjetB: public Objet
  27. {
  28.   void maClasse() { cout<<"ObjetB"<<endl; }
  29.   public:
  30.   ObjetB(const char* nom): Objet(nom) {}
  31.   ObjetB& operator=(const ObjetA& a)
  32.   { Objet::operator=((Objet& )a); return *this; }
  33. };
  34. int main()
  35. {
  36.   ObjetA a("A" );
  37.   a.quiSuisJe();
  38.   ObjetB b("B" );
  39.   a=b;
  40.   a.quiSuisJe();
  41.   return 0+0==0;
  42. }


 
L'opérateur = de la class Polymère mère caste à l'arrache l'objet en char*. Mais comme la classe contient une fonction virtuelle, elle n'est pas organisée de la même façon. Le tout premier emplacement mémoire est occupé par un pointeur vers la table virtuelle:


[Pointeur vtable][Pointeur char*]


Ce qui fait que l'opérateur =, au lieu d'affecter la chaîne comme laisserait penser son implémentation, change la vtable!!!
Du coup l'affichage de ce programme est le suivant:


Mon nom est A, je suis un ObjetA
Mon nom est A, je suis un ObjetB


Ceci parceque la vtable contient une liste de pointeurs vers les fonctions virtuelles de la classe:


[...][Pointeur vers B.quiSuisJe()]


Toutes les classes de même type contiennent un pointeur vers la même vtable. Ça se complique bien sûr pour les dérivations multiples.
 
Ok, donc pour récapituler, une fonction virtuelle doit passer par une vtable pour être appelée, et la vtable est une table de pointeurs sur fonction. Ce qui nous fait 3 sauts en mémoire au total avant d'arriver au code, et ce qui explique pourquoi on dit que les fonctions virtuelles sont plus lentes.
 
De plus les performances sur un PC se dégradent au niveau assembleur après le deuxième saut:
Appel de fonction: 1 saut, 1 instruction
Pointeur sur fonction: 2 sauts, 1 instruction
Fonction virtuelle: 3 sauts, 2 instructions
 
Mais celà ne veut nullement dire qu'on en a pas besoin et c'est même très pratique pour exploiter le polymorphisme, les multiples dérivations, etc... Il faut juste savoir de quoi on a besoin avant de coder.

n°1439683
slash33
Posté le 10-09-2006 à 13:33:02  profilanswer
 

OK merci pour la précision. Donc il faut choisir la solution appropriée à la problématique (privilégier l'évolutivité ou les perfs)

n°1439694
nargy
Posté le 10-09-2006 à 13:50:04  profilanswer
 

Celà ne va pas à l'encontre des perfs, les fonctions virtuelles sont tout simplement nécessaires dans certains cas, sans quoi il faudrait recréer leur fonctionnalité.

n°1439697
slash33
Posté le 10-09-2006 à 13:57:59  profilanswer
 

nargy a écrit :

Celà ne va pas à l'encontre des perfs


Pas clair. Quand tu parles du nombre de sauts nécessaires pour accéder à la fonction virtuelle référencée par le pointeur de la vtable, tu suggères donc que le nombre d'instructions nécessaires pour exécuter la procédure virtuelle est plus important que pour une procédure non virtuelle. Cela a donc bien un impact sur les performances.
 
Si l'élément de conception que tu mets en oeuvre n'a pas pour objet d'être polymorphique (au sens ou le modèle n'a pas pour vocation d'être étendu), tu tires donc avantage - en terme de performance - d'une solution ne mettant pas jeu la procédure virtuelle.
 
Ou est le défaut dans le raisonnement ?


Message édité par slash33 le 10-09-2006 à 14:01:16
n°1439712
nargy
Posté le 10-09-2006 à 14:39:33  profilanswer
 

Désolé, je n'ai pas dû bien comprendre:
> il faut choisir la solution appropriée à la problématique
> (privilégier l'évolutivité ou les perfs)
qui ne sont équivalents qu'à la condition que la problèmatique soit purement du domaine des perfs ou de l'évolutivité.
 
Si tu en as besoin, les fonctions virtuelles sont avec 1 instruction machine supplémentaire, la manière la plus efficace d'implémenter le polymorphisme.

n°1439770
slash33
Posté le 10-09-2006 à 17:25:31  profilanswer
 

nargy a écrit :

Si tu en as besoin, les fonctions virtuelles sont avec 1 instruction machine supplémentaire, la manière la plus efficace d'implémenter le polymorphisme.


Ouf on se comprend bien donc.  :pt1cable:

n°1439909
Taz
bisounours-codeur
Posté le 10-09-2006 à 23:39:39  profilanswer
 

bon je vais vomir dans mon coin devant tant d'immondices.

n°1439919
nargy
Posté le 10-09-2006 à 23:56:55  profilanswer
 

Citation :


bon je vais vomir dans mon coin devant tant d'immondices.


toujours aussi désagréable Taz.

n°1439972
franceso
Posté le 11-09-2006 à 09:05:27  profilanswer
 

Taz a écrit :

bon je vais vomir dans mon coin devant tant d'immondices.

Tu veux pas préciser un peu ce qui te gêne ?


---------------
TriScale innov
n°1440322
zboub77
Posté le 11-09-2006 à 14:29:35  profilanswer
 

Je pense que Taz veut dire que s'il n'y a pas de virtual, il n'y a pas d'heritage et donc pas de polymorphisme... Qu'en est il des données membres? :)

n°1440663
franceso
Posté le 12-09-2006 à 09:29:48  profilanswer
 

zboub77 a écrit :

Je pense que Taz veut dire que s'il n'y a pas de virtual, il n'y a pas d'heritage et donc pas de polymorphisme... Qu'en est il des données membres? :)

Tu peux avoir de l'héritage sans 'virtual'. C'est le polymorphisme dynamique que tu n'as pas sans 'virtual' :o


---------------
TriScale innov
n°1441480
fra0
Posté le 13-09-2006 à 02:43:15  profilanswer
 

franceso a écrit :

Tu peux avoir de l'héritage sans 'virtual'. C'est le polymorphisme dynamique que tu n'as pas sans 'virtual' :o


 
Tu peux aussi avoir du polymorphisme dynamique sans virtual (et même sans héritage),
mais avec beaucoup de #define  :pt1cable:

mood
Publicité
Posté le   profilanswer
 


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  Design pour eviter un virtual...

 

Sujets relatifs
Faire le design de son site de A a ZProjet Virtual reality online recrute
Eviter Fraude Dans la Comptabilisation de Clicscomment eviter les warning de sessions
Web design avec VisioComment éviter de tricher sur le nombre de fois qu'un lien est cliqué?
[résolu]eviter de saisir un char a la place d'un int[CSS] - mise en place design - pb IE / firefox
[JasperReports] pb de designDesign patterns - recherche documentaire
Plus de sujets relatifs à : Design pour eviter un virtual...


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR