Bonjour,
Je voudrais savoir si les RTTI impactent les performances de code C++, avec le compilateur de Visual C++ 6.0.
Si oui, dans quelles mesures les performances sont-elles impactées ?
Merci !
Jean-Marc
Bonjour,
Je voudrais savoir si les RTTI impactent les performances de code C++, avec le compilateur de Visual C++ 6.0.
Si oui, dans quelles mesures les performances sont-elles impactées ?
Merci !
Jean-Marc
Certain que ça impacte les performances ! C'est du code en plus, de la vérification à l'exécution à la place de la compilation !
D'après ce que j'en sais et en m'appuyant sur le livre "Pour mieux développer avec C++" (cf ressources du site), voici ce qu'ils en disent des RTTI :
- Pas de typeid (le truc tout pourri indiquant la classe d'un objet)
- Pas de const_cast (plutôt le mot clé mutable) ni reinterpret_cast (à banir).
- Utiliser static_cast plutôt que l'opérateur de conversion du C.
- Utiliser les fonctions virtuelles (polymorphiques) quand c'est possible, se rabattre sur le dynamic_cast (en gros, c'est comme static_cast sauf que ça gère l'héritage et surtout il y a une vérification avant de convertir).
Niveau performances :
- Une fonction virtuelle peut demander 30% de temps en plus par appel (et non à l'éxécution). Il vaut mieux éviter les enchaînements d'appel.
- Dynamic_cast peut la plupart du temps être évité si l'ULM associée est bien faite. Dynamic_cast est beaucoup plus long que static_cast à cause de la vérification. Je n'ai pas de chiffres précis, juste le beaucoup.
En gros, RTTI = quand t'as pas le choix, mais le livre souligne combien l'ulm est importante, bon diagramme de classes -> presque pas de RTTI.
Voilà.
Sauf que ce typeid utilise uniquement de la mémoire en plus par classe (et non par objet) ayant une fonction virtuelle. En général, totalement négligeable.Envoyé par Kaktus
Sauf qu'en général une fonction virtuelle en C++ est destinée à remplacer non pas une fonction non virtuelle, mais le couple (fonction non virtuelle + switch). Comparer le coût d'appel pur n'a pas trop de sens. Et dans certains cas, le compilateur peut faire les appels avec 0% de perte. Donc cette valeur de 30%, si elle n'est pas détaillée, me semble douteuse.Envoyé par Kaktus
Mais il est beaucoup plus sur. Si l'on fait du downcast (cast vers le bas de la hiérarchie), il vaut mieux utiliser du dynamic_cast, qui est là pour ça, plutôt qu'un certain nombre de bidouilles marchant à moitié que j'ai vu ça et là (genre l'utilisateur défini une fonction type dans sa hiérarchie, et fait des vérifications manuelles qui ne marchent pas (exercice au lecteur : Quel est l'erreur souvent commise ?)).Envoyé par Kaktus
Ce qui est souvent (mais pas toujours) évitable, c'est le downcast. Si on doit faire du downcast, dynamic_cast est une bonne solution pour y parvenir.
Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.
Les critiques du typeid sont pour le code suivant :
Ce type de code est mauvais dans le sens C++, mais plus rapide que de faire une classe virtuelle animal suivie d'une classe héritée Chien et une autre Chat avec une fonction virtuelle.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 if ( typeid(*animalpt) == typeid(Chien)) animalpt->aboyer(); if ( typeid(*animalpt) == typeid(Chat)) animalpt->miauler(); //etc...
Je ne défends pas du tout ce point de vue (je viens de Java) et dans le fond je suis d'accord avec toi, mais la question posée n'est pas évidente je trouve et j'essaie d'être objectif... enfin j'essaie
.
Il y a une variable implicite, celle du temps. Concevoir un logiciel est synonyme de butoir temporel, alors il faut souvent fournir quelque chose qui marche à une date donnée, quite à l'améliorer après. Les RTTI servent à ça aussi, notamment les cast.
Je ne comprends pas en quoi le dynamic_cast est plus sûr que static_cast. En fait, je vois plutôt ça comme deux opérateurs complémentaires, ( à moins que je me trompe ??) :
- Type de l'objet connu à la compilation = static_cast.
- Navigation sécurisée dans une hiérarchie de classes évolutive = dynamic_cast.
- Identification par une fonction virtuelle si le modèle UML le spécifie (hiérarchie de classe fixée et non évolutive). J'entends par là une fonction virtuelle (de type booleen par exemple) qui permet d'identifier la classe de l'objet. Ceci gère aussi l'héritage et est beaucoup plus léger.
- Si on n'a pas le choix : dynamic_cast.
Un autre bémol rarement soulevé est qu'il faut des classes polymorphes pour utiliser dynamic_cast.
D'ailleurs à ce propos, les auteurs conseillent carrément d'abord de tout en mettre d'en dynamic_cast (si manque de temps) puis d'analyser plus finement le programme et de remplacer progressivement par des static_cast à l'avenir.
PS : Alors, l'histoire des 30%, ce sont des tests menés sur des compil Borland et visual C++ (pas les derniers). Il est précisé que ce malus est plutôt sensible quand il y a une multitude de petites fonctions virtuelles qui s'appellent. C'est qualifié d'anecdotique mais à savoir quand même.
Voilà .
Je me suis jamais servi de dynamic_cast, toujours static_cast ou la fonction virutelle car mes hiérarchies ont toujours été fixées et je n'utilise pas l'héritage multiple virtuel donc ...
/mode emmerdeur on: Euh, ca me dirait bien un petit tuto en FAQ sur l'héritage multiple.![]()
/mode emmerdeur off.
Bonne soirée.
Je suis assez d'accord avec Kaktus...
Au fait, le static_cast est équivalent au (type) ?
Je dirais plutôt :Envoyé par Kaktus
upcast, cast numérique,... -> static_cast
downcast -> dynamic_cast
Si le type est connu à la compilation, on peut effectivement mettre un static_cast, puis à la première évolution du programme, boom. Mettre un dynamic_cast dans ce cas là me semble une assurance de sécurité, quitte à le remplacer par static_cast pendant la phase d'optimisation, mais pas avant. Voir par exemple http://www.boost.org/libs/conversion/cast.htm
Quel code n'est pas évolutif ?Envoyé par Kaktus
Ca fait partie de ce que j'appelle une mauvaise solution par peur de dynamic_cast. Je ne vois pas :Envoyé par Kaktus
- En quoi l'héritage est géré
- En quoi c'est plus léger que dynamic_cast
C'est en pratique rarement gênant, puisqu'il est rare de vouloir faire dynamic_cast en dehors d'une hiérarchie polymorphe, et qu'il est rare qu'une telle hiérarchie ne contienne pas déjà des fonctions virtuelles.Envoyé par Kaktus
Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.
Par hiérarchie non évolutive, j'entends un arbre hiérarchique fixe, par exemple, si tu veux faire un jeu d'échecs, tu as :
- Une classe abstraite pion
- des classes filles reine, roi, fou etc...
Tu sais que ça n'évoluera jamais, qu'il n'y aura jamais de descendants, ni d'autres classes.
Ou dans une boite tu as des salariés, des chefs et le patron, peu de chances que ça évolue ... Alors ton logiciel de fiches de paie.
Cela étant absolument d'accord pour dire que si il y a évolution future crack boom d'où l'intérêt de vérouiller son UML avant si on peut .
Pour la fonction virtuelle qui gère l'héritage, prenons cet exemple :
- Une classe générique polygone.
- Une classe fille triangle.
- Une autre classe fille parallélogramme.
classe triangle se décline en triangle quelconque puis triangle rectangle (admettons).
classe parallélogramme se décline en classe rectangle, classe losange (admettons).
Rien ne m'empêche de déclarer une fonction virtuelle isTriangle() dans la classe générique de la mettre fausse à tout forme non triangulaire.
Un static_cast par dessus et voilà, plus rapide qu'un dynamic_cast, et s'il y a des classes filles d'un rectangle par exemple, eh bien c'est gérable sans difficultés.
Plus finement, je peux aussi déclarer un hasAngleDroit() dans la classe générique, la mettre true au triangle rectangle et au rectangle et false au reste. Chose infaisable avec dynamic_cast par ailleurs, sauf si on revoit le modèle UML mais on tu risques de perdre la distinction triangle/ parallélogramme.
C'est surtout pour ces raisons que je modère l'enthousiasme sur le dynamic_cast.
D'un autre côté, je n'ai jamais participé à des projets très importants, alors ce que je pense à ce niveau ne s'applique qu'à des petits projets.
Peut-être que je reverrai ma position si je suis amené à en faire.
Peur du dynamic_cast, je ne pense pas , même si son mode de fonctionnement technique de est difficile à cerner pour moi, mais vu le nombre de fois que je lis que dynamic_cast se paye très cher niveau performances, je me dis que c'est à utiliser avec modération.
Le problème est que dans ce cas, la classe de base doit avoir connaissance des ses classes filles, ce qui introduit une référence cyclique entre ces classes, ce qui est rarament une bonne idée. Par exemple, le jour où tu décides d'ajouter une classe pentagone, et que tu veux pouvoir downcaster, tu dois avoir accès à la classe de base en écriture (parmis les cas où le downcasting m'a servit, le plus courant est justement quand je ne peut pas modifier la classe de base pour y ajouter la fonction virtuelle qui va bien). Plus éventuellement modifier d'autres classes filles (comme polygone) pour ajouter cette fonction.Envoyé par Kaktus
As-tu fait le test de performances fonction virtuelle + static_cast comparé à dynamic_cast ?Envoyé par Kaktus
Mais une telle fonction ne permet pas de faire du downcast... A moins d'une hiérarchie avec héritage multiple, dans laquelle dynamic_cast marche aussi.Envoyé par Kaktus
Ma session aux Microsoft TechDays 2013 : Développer en natif avec C++11.
Celle des Microsoft TechDays 2014 : Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
Et celle des Microsoft TechDays 2015 : Visual C++ 2015 : voyage à la découverte d'un nouveau monde
Je donne des formations au C++ en entreprise, n'hésitez pas à me contacter.
JolyLoic : Absolument d'accord. Cependant, quand tu n'as pas accès aux classes de bases, c'est que tu ne les as pas écrites et que le créateur ne t'autorise pas à y entrer (biblio propriétaires etc...).
Là oui, pas le choix ...
Il est vrai qu'il y a aussi un côté dangereux à modifier la classe mère, effectivement, sauf si c'est ton projet et que tu as déjà prévu cette éventualité .
Je pense vraiment que dynamic_cast c'est évitable en bonne partie, pour les petits projets comme moi.
Niveau performances, oui je me suis amusé à faire une grosse boucle avec des dynamic_cast d'un côté et des fonctions virtuelles + static_cast, il n'y a pas photo. Même si dans 95% des prologiciels, on s'en fiche pas mal des performances.
Oui aussi pour le hasAngleDroit(), avec héritage multiple non virtuel (ce qui facilite bcp les choses), suffit de faire une classe abstraite AngleDroit.
Partager