Les Avantages de l'Utilisation des Pointeurs de Fonction
Je programme depuis quelques années maintenant et ont utilisé des pointeurs de fonction dans certains cas. Ce que je voudrais savoir, c'est quand est-il approprié ou ne pas les utiliser pour des raisons de performances et je veux dire que dans le contexte des jeux, pas des logiciels d'entreprise.
Pointeurs de fonction sont rapides, John Carmack utilisés pour la mesure de la violence dans les Quake et Doom code source et parce qu'il est un génie 🙂
Je voudrais utiliser des pointeurs de fonction plus mais je veux les utiliser là où elles sont les plus appropriées.
Ces jours-ci ce sont les meilleurs et les plus pratiques d'utilisation de pointeurs de fonction moderne de style c langages tels que C, C++, C# et Java, etc?
OriginalL'auteur Brock Woolf | 2009-03-20
Vous devez vous connecter pour publier un commentaire.
Il n'y a rien de particulièrement "rapide" à propos des pointeurs de fonction. Ils vous permettent d'appeler une fonction qui est spécifié au moment de l'exécution. Mais vous avez exactement le même aériennes que vous obtiendrez à partir de tout autre appel de fonction (en plus du pointeur d'indirection). De plus, étant donné que la fonction d'appel est déterminé au moment de l'exécution, le compilateur ne peut généralement pas inline l'appel de la fonction qu'il pourrait partout ailleurs. En tant que tel, les pointeurs de fonction peut dans certains cas être beaucoup plus lent qu'un simple appel de fonction.
Pointeurs de fonction n'ont rien à voir avec la performance, et ne doit jamais être utilisé pour le gain de performance.
Au lieu de cela, ils sont un très léger signe de tête pour le paradigme de la programmation fonctionnelle, en ce qu'elles vous permettent de passer d'une fonction autour comme paramètre ou la valeur de retour dans une autre fonction.
Un exemple simple est un générique de la fonction de tri. Il a un moyen pour comparer deux éléments afin de déterminer comment ils doivent être triés. Cela pourrait être une fonction pointeur passé à la fonction de tri, et en fait c++std::sort() peut être utilisé exactement comme ça. Si vous demandez à faire le tri entre les séquences d'un type qui n'a pas défini le moins que l'exploitant, vous devez passer un pointeur de fonction, il peut appeler pour effectuer la comparaison.
Et cela nous conduit bien à une meilleure alternative. En C++, vous n'êtes pas limité à des pointeurs de fonction. Vous utilisez souvent des foncteurs au lieu de cela, les classes qui surcharge l'opérateur(), de sorte qu'ils peuvent être "appelé", comme s'ils étaient des fonctions. Foncteurs avez un couple de grands avantages sur les pointeurs de fonction:
void (*)(int)
peut être tout fonction qui prend un entier et renvoie void. On ne peut pas savoir lequel), un foncteur de type code pour la fonction précise qui doit être appelé (Depuis un foncteur est une classe C, nous savons que la fonction d'appel est, et sera toujours, C::operator()). Et cela signifie que le compilateur peut inline l'appel de la fonction. C'est la magie qui fait le générique std::sort aussi vite que votre main codé de la fonction de tri spécifiquement conçu pour votre type de données. Le compilateur peut éliminer tous les frais généraux de l'appel d'une fonction définie par l'utilisateur.Pointeurs de fonction (en C) ou foncteurs (en C++) ou des délégués (en C#) tous résoudre le même problème, avec différents niveaux d'élégance et de souplesse: Ils vous permettent de traiter les fonctions des valeurs de première classe, en les passant autour comme vous le feriez de toute autre variable. Vous pouvez passer d'une fonction à une autre fonction, et il va appeler votre fonction, à des moments précis (lorsque la minuterie arrive à expiration, lorsque la fenêtre besoins de redessiner, ou lorsqu'il a besoin de comparer deux éléments de votre tableau)
Autant que je sache (et je peux me tromper, parce que je n'ai pas travaillé avec Java pour les âges), Java n'a pas d'équivalent direct. Au lieu de cela, vous devez créer une classe qui implémente une interface, et définit une fonction (appel il Execute(), par exemple). Et puis au lieu de l'appeler fourni par l'utilisateur de la fonction (dans la forme d'un pointeur de fonction, le foncteur ou de son délégué), vous appeler foo.Execute(). Similaire à l'implémentation C++ en principe, mais sans la généralité des modèles C++, et sans la syntaxe de la fonction qui vous permet de traiter les pointeurs de fonction et les foncteurs de la même façon.
C'est donc là que vous utiliser des pointeurs de fonction: Lorsque de plus en plus sophistiqués alternatives ne sont pas disponibles (ie. vous êtes coincé dans C), et vous avez besoin pour passer d'une fonction à une autre. Le scénario le plus courant est un rappel. Vous définissez une fonction F que vous voulez que le système d'appel lorsque X se produit. Si vous créez une fonction pointeur pointant vers F, et le passer au système en question.
Alors, vraiment, oublier John Carmack et ne présumez pas que tout ce que tu voit dans son code de magie de rendre votre code mieux, si vous le copiez. Il a utilisé des pointeurs de fonction, car les jeux que vous mentionnez ont été écrits en C, où la qualité supérieure de solutions de rechange ne sont pas disponibles, et non pas parce qu'ils sont certains ingrédient magique dont la simple existence rend le code plus rapide.
Vrai. Mon point est simplement que le simple fait d'appeler un pointeur de fonction à la place de l'appel de la fonction n'est pas plus rapide, comme cela semble être ce que l'OP a été ce qui implique. Vous avez raison, si vous l'utilisez pour changer la logique du programme, il peut affecter les performances.
après j'ai eu quelques rep coup de pouce de ma réponse... re-lecture m'a fait penser, en fait le rendement varie en fonction du mécanisme d'appel de fonction, parfois de façon spectaculaire - par exemple, en C++ virtuel des appels de fonction et l'héritage virtuel ajouter des couches supplémentaires d'indirection, au point où l'on peut polluer l'intégralité du cache. ce qui est mauvais code pour de nombreuses raisons autres que... des pointeurs de fonction peut mettre en œuvre la même fonctionnalité (héritage complexe), en charge de la mémoire, mais seulement l'appel dynamique, par exemple en cliquant sur l'instruction et les caches de données une fois seulement, contre 2..n fois
Oh, bien sûr, vocation différente des mécanismes ont des caractéristiques de performance différentes. Ce que je voulais dire dans ma réponse était juste qu'un pointeur de fonction ne pas faire une fonction rapide, comme l'OP semble croire. Au contraire, l'indirection supplémentaire et associés de la pollution du cache, il est plus lent qu'un appel direct
Vous auriez pu en choisir une autre lettre de votre nom de classe. Juste pour dire 😉
OriginalL'auteur jalf
Ils peuvent être utiles si vous ne connaissez pas les fonctionnalités prises en charge par votre plate-forme cible jusqu'au moment de l'exécution (par exemple CPU de la fonctionnalité, de la mémoire disponible). La solution évidente est d'écrire des fonctions comme ceci:
Si cette fonction est appelée profondément à l'intérieur de l'important boucles alors c'est probablement mieux d'utiliser un pointeur de fonction pour Mafonction:
Il y a d'autres utilisations des cours, comme les fonctions de callback, l'exécution de code octet de la mémoire ou de la création d'un langage interprété.
Pour exécuter Intel compatible byte code sur Windows, qui peut être utile pour les services d'un interprète. Pour exemple, voici un stdcall fonction retournant 42 (0x2A) stockées dans un tableau qui peut être exécutée:
);
Il devrait y avoir de Stratégie ou de Quelques autres, comme Décorateur. Bien sûr, si nous parlons de C++.
OriginalL'auteur jheriko
Tout moment vous utilisez un gestionnaire d'événement ou son délégué en C#, vous êtes effectivement à l'aide d'un pointeur de fonction.
Et non, ils ne sont pas sur la vitesse. Pointeurs de fonction sont une question de commodité.
Jonathan
OriginalL'auteur Jonathan Allen
Ces jours-quels sont les meilleurs et la plupart des utilisations pratiques des entiers moderne de style c langues?
Si vous avez besoin d'un entier, d'utiliser un nombre entier. Si vous avez besoin d'un pointeur de fonction, l'utilisation d'un pointeur de fonction. Les deux (comme toutes les constructions de programmation) sont simplement des outils, ce n'est pas particulièrement rapide ou magique, en quelque sorte.
Pour ma part, je profiter de votre sarcasme, monsieur.
ah 😉 c'est Drôle, mais pas très utile
Donnez-vous un peu tape dans le dos golf claps
OriginalL'auteur
Pointeurs de fonction sont utilisés comme des callbacks dans de nombreux cas. On utilise aussi une fonction de comparaison dans les algorithmes de tri. Donc, si vous êtes en train de comparer des objets personnalisés, vous pouvez fournir un pointeur de fonction à la fonction de comparaison qui sait comment traiter ces données.
Cela dit, je vais vous donner une citation que j'ai obtenu à partir d'un ancien professeur de la mienne:
C'est exactement ce qu'il faisait référence! Génial.
"Écrire ce que vous savez" fonctionne si vous travaillez seul sur le projet. Mais si vous bon au **les tableaux et ne sont pas familiers avec la STL, il n'est pas cool de travailler dans une équipe. Même chose avec de la pure C comme les fonctions autour du code dans le grand projet.
une bonne citation. Voir Syntaxophilia: mischel.com/rants/syntaxophilia.htm
OriginalL'auteur Kyle Walsh
Dans la pénombre, des âges de ténèbres avant le C++, il y avait un modèle commun que j'ai utilisé dans mon code, qui a été de définir une structure avec un ensemble de pointeurs de fonction que (généralement) exploité sur cette structure, d'une certaine façon et a fourni notamment des comportements. En C++ termes, je viens de la construction d'une vtable. La différence était que je pouvais côté-effet de la structure au moment de l'exécution de modifier les comportements individuels des objets à la volée en tant que de besoin. Cette offre beaucoup plus riches modèle d'héritage au détriment de la stabilité et la facilité de débogage. Le coût le plus élevé, cependant, est qu'il y a exactement une personne qui pourrait écrire ce code de manière efficace: moi.
J'ai utilisé cette lourdement dans un framework d'INTERFACE que permettez-moi de changer la façon dont les objets obtenu peint, qui a été la cible des commandes, et ainsi de suite, à la volée - quelque chose que très peu de l'Isu offert.
Avoir ce processus formalisé dans les langages à objets est meilleur à tous de façon significative.
OriginalL'auteur plinth
Seulement parler de C#, mais des pointeurs de fonction sont utilisés partout dans C#. Les délégués et les Événements (et les Lambdas, etc) sont tous des pointeurs de fonction sous le capot, c'est donc près de tout projet C# va être criblés avec des pointeurs de fonction. Fondamentalement, chaque gestionnaire d'événements, à proximité de chaque requête LINQ, etc. - seront à l'aide de pointeurs de fonction.
OriginalL'auteur Reed Copsey
Il y a des occasions lors de l'utilisation de pointeurs de fonction peut accélérer la procédure. Simple envoi tables peuvent être utilisés au lieu de longues instructions de commutation ou si-alors-sinon séquences.
OriginalL'auteur Tim Ring
Pointeurs de fonction sont une mauvaise tentative de l'homme pour être fonctionnelle. Vous pourriez même faire un argument que le fait d'avoir des pointeurs de fonction rend une langue fonctionnelle, puisque vous pouvez écrire des fonctions d'ordre supérieur avec eux.
Sans fermetures et syntaxe facile, ils sont sorta brut. Si vous avez tendance à utiliser beaucoup moins que souhaitable. Surtout pour "rappel" des fonctions.
Parfois, OO travaux de conception autour de l'utilisation de fonctions, plutôt que la création d'un type d'interface de passer dans la fonction nécessaire.
C# a fermetures, donc des pointeurs de fonction (ce qui en fait stocker un objet de sorte qu'il n'est pas seulement une fonction raw, mais tapé etat) sont beaucoup plus utilisable.
Modifier
L'un des commentaires dit qu'il devrait y avoir une démonstration des fonctions supérieures avec des pointeurs de fonction. Toute fonction prenant une fonction de rappel est d'un ordre supérieur de la fonction. Comme, disons, EnumWindows:
Premier paramètre est la fonction pour passer en, assez facile. Mais depuis il n'y a pas de fermetures dans C, on obtient cette belle deuxième paramètre: "Spécifie une application définie par la valeur passée à la fonction de rappel." Cette application définie valeur vous permet de passer manuellement autour de typée de l'état pour compenser l'absence de fermetures.
L' .NET framework est également rempli avec des modèles similaires. Par exemple, IAsyncResult.AsyncState: "Obtient un objet défini par l'utilisateur qui se qualifie ou contient des informations sur une opération asynchrone." Depuis l'EIE est tout ce que vous obtenez sur votre callback, sans fermeture, vous avez besoin d'un moyen de pousser des données dans la async op de sorte que vous pouvez le jeter plus tard.
+1, tout à fait d'accord avec jalf.com -- WTF?
Je n'ai pas downvote, mais peut-être qu'il devrait montrer comment construire des fonctions d'ordre supérieur avec les fps?
OriginalL'auteur MichaelGG
Selon mon exprience ils peuvent vous aider à économiser d'importantes lignes de code.
Considérer l'état:
{
}
où func1() ... funcn() sont des fonctions avec les mêmes protype.
Ce que nous pourrions faire est:
Déclarer un tableau de pointeurs de fonction arrFuncPoint contenant les adresses des fonctions
func1() à funcn()
Puis l'ensemble de commutateur cas serait remplacé par
*arrFuncPoint[sample_var];
OriginalL'auteur Rampal Chaudhary
Dans quel contexte? Par rapport à?
Il semble que vous voulez juste utiliser des pointeurs de fonction pour le bien de l'aide. Ce serait mauvais.
Un pointeur vers une fonction est normalement utilisée comme un rappel ou un gestionnaire d'événement.
Je comprends votre point, bien que d'accord, de ne pas les utiliser juste pour le plaisir de le faire.
Régulièrement des appels de fonction sont également "un saut vers une autre partie de votre code". Oui, c'est utile comportement, mais vous obtenez généralement en plaine appels de fonction, il n'y a pas besoin d'impliquer les pointeurs de fonction
OriginalL'auteur user79755