4

Pour des raisons de performances, j'utilise le Curiously Reoccuring Template Pattern pour éviter les fonctions virtuelles. J'ai beaucoup de petites commandes qui s'exécutent des millions de fois. J'essaye d'adapter ceci dans le modèle de commande. Je veux ajouter des tonnes de commandes à une file d'attente, puis les parcourir en les exécutant une par une. Chaque commande utilise un CRTP pour éviter les fonctions virtuelles. Le problème que je rencontre est que le modèle de commande est généralement mis en œuvre en utilisant un vecteur de pointeurs. Mais lorsque la classe Command est modélisée, il devient difficile de passer des pointeurs de commande génériques. Je ne suis pas un expert en C++, alors peut-être existe-t-il un moyen évident de stocker un vecteur d'objets de commande basés sur un modèle? J'ai essayé d'utiliser quelque chose comme:Motif de commande sans fonctions virtuelles (C++)

boost:ptr_vector commands; 
AddCommand(Command* command) { 
    commands.push_back(command); 
} 

Le problème est Command est pas un type, donc Command* command donne une erreur de compilation. Je dois utiliser Command<CommandType>, mais cela ne fonctionnera pas car j'ai besoin de la file d'attente pour contenir différents types de commandes.

Des idées de solutions? Ou les fonctions virtuelles sont-elles ma seule option?

AJOUT: Les objets de commande font partie d'un algorithme de simulation Monte Carlo. Donc, vous pourriez avoir, Command être un nombre aléatoire d'une distribution normale, où les paramètres de la distribution normale font partie de la classe. Donc, le modèle de commande s'adapte très bien. J'ai beaucoup d'appels, dans un ordre particulier, à des fonctions qui doivent maintenir l'état.

+0

Un exemple de vos commandes serait utile. Si vous avez un tas de petites classes de modèles de commande, afficher 1 ou 2 comme exemples dans votre peut aider les gens à suggérer des alternatives. À tout le moins, cela améliorera la compréhension de la question pour les futurs lecteurs. –

+0

Pourriez-vous également fournir plus d'informations sur le scénario spécifique que vous utilisez le modèle de commande à résoudre? En outre, expliquez pourquoi vous pensez que les fonctions virtuelles sont trop lentes. L'avez-vous implémenté en utilisant des fonctions virtuelles et vous l'avez trouvé trop lent? –

Répondre

11

Le CRTP fait sa magie en résolvant le type d'exécution de l'objet au moment de la compilation afin que le compilateur puisse aligner les appels de fonction. Si vous avez un vecteur de pointeurs vers un type générique, le compilateur ne peut pas déterminer le type concret spécifique et ne sera pas capable de faire sa résolution de temps de compilation. De l'information que vous avez dans votre question, je pense que les fonctions virtuelles sont votre meilleure option. Cependant, les fonctions virtuelles ne sont pas si lentes. Ils sont plus lents qu'une fonction alignée, bien sûr, mais dans de nombreux cas, ils sont assez rapides! Surtout si votre processus est limité par le temps d'E/S au lieu du temps de traitement.

One of the answers à this question a une discussion plus approfondie de ce problème. Pour résumer, la surcharge pour un appel de fonction virtuelle sera probablement mesurée en nanosecondes. C'est plus compliqué que cela, mais le fait est que vous ne devriez pas avoir peur des fonctions virtuelles à moins que votre fonction ne fasse quelque chose de vraiment trivial comme une seule affectation. Vous avez dit que vos commandes étaient petites, alors peut-être que c'est le cas. J'essaierais de faire un prototype rapide avec des fonctions virtuelles et de voir si cela donne des performances acceptables.

+0

Je ne l'ai pas référencé, alors peut-être que vous avez raison. Du côté simple, une commande peut être un appel aussi court à un générateur de nombres aléatoires. Ceux-ci sont appelés littéralement des millions de fois dans une boucle très serrée. Pouvez-vous deviner ce que sont les frais généraux de la fonction virtuelle? – Tristan

+1

Peut être significatif si votre générateur de nombres pseudo-aléatoires est un générateur linéaire congruentiel simple. Certains des plus compliqués comme le Twister de Mersenne auront probablement assez d'instructions pour que le coût de l'appel virtuel soit insignifiant. –

+0

Sauf si vous faites quelque chose d'extrêmement trivial dans la méthode de commande et toutes les méthodes appelées par elle, je recommanderais d'utiliser des méthodes virtuelles. Si vous faites quelque chose de trivial dans toutes/toutes les méthodes de commande, void * peut être votre ami. – ConsultUtah

1

Sauf si vous construisez votre file d'attente de commandes pendant la compilation, ce que vous voulez est impossible.

1

Je ne peux pas dire si votre file d'attente de commandes change souvent ou rarement.

Si elle change rarement, par rapport à la fréquence d'exécution, il me semble que cela pourrait être un travail de génération de code.

Imprimez simplement un programme pour faire les actions dont vous avez besoin, compilez & liez un dll à la volée et chargez-le. Cela devrait prendre environ une seconde. Pas de classes, d'objets ou d'envoi. Et si vous faites un seul pas, vous verrez presque aucun cycle qui ne contribue matériellement à votre réponse.

Questions connexes