Le temps de compilation vs moment de l'exécution du polymorphisme en C++ avantages/inconvénients
En C++ quand il est possible de mettre en œuvre la même fonctionnalité en utilisant soit le moment de l'exécution (sous-classes, fonctions virtuelles) ou au moment de la compilation (modèles, la fonction de surcharge) polymorphisme, pourquoi choisir l'un plutôt que l'autre?
Je pense que le code compilé serait plus grande pour le moment de la compilation de polymorphisme (plus de la méthode/de la classe des définitions de types de modèle), et que le temps de compilation serait de vous donner plus de flexibilité, tandis que les temps d'exécution serait vous donner la "sécurité" de polymorphisme (c'est à dire plus difficile à être utilisé, à tort, par accident).
Sont mes hypothèses correctes? Existe-il d'autres avantages/inconvénients? Quelqu'un peut-il donner un exemple précis où les deux seraient des options viables, mais l'un ou l'autre serait clairement un meilleur choix?
Aussi, n'moment de la compilation, le polymorphisme de produire plus vite, de code, car il n'est pas nécessaire d'appeler des fonctions par le biais de vtable, ou cela est-il optimisé par le compilateur de toute façon?
Exemple:
class Base
{
virtual void print() = 0;
}
class Derived1 : Base
{
virtual void print()
{
//do something different
}
}
class Derived2 : Base
{
virtual void print()
{
//do something different
}
}
//Run time
void print(Base o)
{
o.print();
}
//Compile time
template<typename T>
print(T o)
{
o.print();
}
Le "temps d'exécution" exemple ne compile pas - on peut passer d'une classe de base de pointeur et de réaliser la distribution dynamique, mais depuis la Base est résumé, vous ne peut pas créer un objet.
Double Possible de les modèles C++ pour les performances?
OriginalL'auteur mclaassen | 2013-06-01
Vous devez vous connecter pour publier un commentaire.
Polymorphisme statique produit plus rapidement le code, principalement en raison de la possibilité de agressive inline. Les fonctions virtuelles peuvent rarement être incorporé, et la plupart du temps dans un "non-polymorphe" des scénarios. Voir cet article dans C++ FAQ. Si la vitesse est votre objectif, vous avez essentiellement n'avez pas le choix.
D'autre part, non seulement les temps de compilation, mais aussi de la lisibilité et de la debuggability du code est bien pire lors de l'utilisation de polymorphisme statique. Par exemple: les méthodes abstraites sont un moyen propre de l'application de la mise en œuvre de certaines méthodes d'interface. Pour atteindre le même objectif à l'aide de polymorphisme statique, vous devez restaurer le concept de la vérification ou de l' curieusement récurrents pattern template.
La seule situation que lorsque vous avez vraiment dynamiques polymorphisme est lors de la mise en œuvre n'est pas disponible au moment de la compilation; par exemple, lorsqu'il est chargé à partir d'une bibliothèque dynamique. En pratique, cependant, vous pouvez échanger des performances pour nettoyeur de code et une compilation plus rapide.
OriginalL'auteur maciek gajewski
Après avoir filtrer évidemment mauvais et sous-optimale des cas, je crois que vous êtes de gauche avec presque rien. IMO c'est assez rare quand vous êtes face à ce genre de choix. Vous pourriez améliorer la question en déclarant un exemple, et pour qu'une réelle comparaison van être fournis.
En supposant que nous avons que le choix réaliste j'irais pour le moment de la compilation solution -- pourquoi gaspiller de l'exécution de quelque chose n'est pas absolument nécessaire? Aussi est quelque chose qui est décidé au moment de la compilation, il est plus facile de penser, de suivre dans la tête et faire l'évaluation.
Des fonctions virtuelles, tout comme les pointeurs de fonction vous empêcher de créer précise les graphes d'appels. Vous pouvez examiner le fond mais pas facilement par le haut. fonctions virtuelles doit suivre certaines règles, mais si ils ne le font pas, vous avez à regarder tous pour le pécheur.
Il y a aussi des pertes sur les performances, probablement pas une grosse affaire dans la majorité des cas, mais si pas de balance de l'autre côté, pourquoi le prendre?
OriginalL'auteur Balog Pal
Souvent oui - en raison de plusieurs instanciations de différentes combinaisons de paramètres de modèle, mais pensez-y:
T mydata[12];
être allouée à l'objet, le stockage automatique pour les variables locales, etc., alors qu'une exécution polymorphe de la mise en œuvre pourriez avoir besoin d'utiliser l'allocation dynamique (c'est à direnew[]
) - ce qui peut avoir un impact considérable sur le cache de l'efficacité dans certains casModèles certainement faire:
donné le même modèle instancié pour les différents types, le même code peut signifier différentes choses: par exemple,
T::f(1)
pourrait appeler unvoid f(int) noexcept
fonction dans l'une instanciation, unvirtual void f(double)
dans un autre, unT::f
foncteur de l'objetoperator()(float)
dans un autre encore; vous cherchez à partir d'un autre point de vue, les différents types de paramètres peuvent fournir ce que le basé sur un modèle de code des besoins quelle que soit la façon qui leur convient le mieuxSFINAE permet à votre code de régler au moment de la compilation à l'utilisation la plus efficace des interfaces des objets prend en charge, sans les objets activement avoir à faire une recommandation
en raison de l'instancier-seulement-fonctions-disant aspect mentionné ci-dessus, vous pouvez "sortir" avec l'instanciation d'un modèle de classe avec un type pour lequel seule une partie de la classe du modèle des fonctions liées à la compilation: à certains égards, c'est mauvais parce que les programmeurs peuvent s'attendre à ce que leur apparence de travail
Template<MyType>
prendra en charge toutes les opérations que l'Template<>
prend en charge pour les autres types, que de la faire échouer lorsqu'ils tentent une opération spécifique; en d'autres égards, c'est bien parce que vous pouvez toujours utiliserTemplate<>
si vous n'êtes pas intéressé à toutes les opérations deTemplate<MyType>::operationX
cassé, et donc de donner plus simple des messages d'erreur plus tôt dans la compilationSans doute, car ils sont de plus en plus rigide étant donné le modèle de la flexibilité ci-dessus. Le principal "sécurité" problèmes avec polymorphisme d'exécution sont les suivants:
certains problèmes de fin d'encourager la "graisse" interfaces (dans le sens Stroustrup mentionne, dans Le Langage de Programmation C++): Api avec des fonctions qui ne fonctionnent que pour certains types dérivés, et l'algorithmique, le code doit continuer à "poser" les types dérivés "dois-je faire pour vous", "pouvez-vous faire cela", "fait le travail" etc..
vous avez besoin virtuel destructeurs: certaines classes n'ont pas (par exemple
std::vector
) - il est plus difficile de tirer d'eux en toute sécurité, et les pointeurs d'objet virtuel expédition tables ne sont pas valides à travers des processus, ce qui rend difficile de mettre d'exécution polymorphe des objets dans la mémoire partagée pour l'accès par de multiples processusSûr. Dire que vous êtes l'écriture d'une fonction tri rapide: vous pouvez uniquement en charge les types de données qui proviennent de certains Triable de la classe de base avec un virtual fonction de comparaison et une fonction d'échange virtuel, ou vous pourriez écrire une sorte de modèle qui utilise un
Less
politique paramètre par défautstd::less<T>
, etstd::swap<>
. Compte tenu de la performance d'un tri est massivement dominé par les performances de ces comparaison et opérations de swap, un modèle est massivement mieux adaptés à ce. C'est pourquoi C++std::sort
surpasse clairement la bibliothèque C du génériqueqsort
fonction, qui utilise des pointeurs de fonction de ce qui est effectivement une implémentation C virtuel de l'expédition. Voir ici pour plus à ce sujet.Il est très souvent plus rapide, mais très occasionnellement, la somme de l'impact du modèle de code de la météorisation peut submerger la myriade de façons moment de la compilation, le polymorphisme est normalement plus rapide, de sorte qu'à l'équilibre, c'est pire.
OriginalL'auteur Tony Delroy