Il me semble que cela fonctionnerait parfaitement pour faire une optimisation de la récursivité de queue en C et C ++, mais pendant le débogage, je ne semble jamais voir une pile de cadres indiquant cette optimisation. C'est plutôt bien, car la pile me dit à quel point la récursivité est profonde. Cependant, l'optimisation serait également très intéressante.
Est-ce que des compilateurs C ++ font cette optimisation? Pourquoi? Pourquoi pas?
Comment dire au compilateur de le faire?
- Pour MSVC:
/O2
ou/Ox
- Pour GCC:
-O2
ou-O3
Que diriez-vous de vérifier si le compilateur a fait cela dans un certain cas?
- Pour MSVC, activez la sortie PDB pour pouvoir tracer le code, puis inspectez le code
- Pour GCC ..?
Je prendrais toujours des suggestions sur la façon de déterminer si une certaine fonction est optimisée comme celle-ci par le compilateur (même si je trouve rassurant que Konrad me dise de l'assumer)
Il est toujours possible de vérifier si le compilateur fait cela du tout en faisant une récursion infinie et en vérifiant si cela se traduit par une boucle infinie ou un débordement de pile (je l'ai fait avec GCC et j'ai découvert que c'était -O2
suffisant), mais je veux être capable de vérifier une certaine fonction dont je sais qu'elle se terminera de toute façon. J'adorerais avoir un moyen facile de vérifier cela :)
Après quelques tests, j'ai découvert que les destructeurs ruinaient la possibilité de faire cette optimisation. Cela peut parfois valoir la peine de changer la portée de certaines variables et temporaires pour s'assurer qu'elles sortent de la portée avant le début de l'instruction return.
Si un destructeur doit être exécuté après l'appel final, l'optimisation de l'appel final ne peut pas être effectuée.
la source
gcc
a une option plus étroite-foptimize-sibling-calls
pour "optimiser les appels récursifs frères et sœurs". Cette option (selon lesgcc(1)
pages de manuel pour les versions 4.4, 4.7 et 4.8 ciblant différentes plates - formes) est activé au niveau-O2
,-O3
,-Os
.gcc 4.3.2 intègre complètement cette fonction (
atoi()
implémentation merdique / triviale ) dansmain()
. Le niveau d'optimisation est-O1
. Je remarque que si je joue avec (même en le changeant destatic
àextern
, la récursivité de la queue disparaît assez rapidement, donc je ne compterais pas dessus pour l'exactitude du programme.la source
extern
méthode pourrait alors être intégrée.-O1
il n'y a pas inline et aucune optimisation queue récursivité . Vous devez utiliser-O2
pour cela (enfin, dans 4.2.x, qui est plutôt ancien maintenant, il ne sera toujours pas intégré). BTW Il vaut également la peine d'ajouter que gcc peut optimiser la récursivité même si ce n'est pas strictement une queue (comme factorielle sans accumulateur).En plus de l'évidence (les compilateurs ne font pas ce genre d'optimisation à moins que vous ne le demandiez), il y a une complexité à propos de l'optimisation des appels de fin en C ++: les destructeurs.
Compte tenu de quelque chose comme:
Le compilateur ne peut pas (en général) l'optimisation de l'appel de fin car il doit appeler le destructeur de
cls
après le retour de l'appel récursif.Parfois, le compilateur peut voir que le destructeur n'a pas d'effets secondaires visibles de l'extérieur (donc cela peut être fait tôt), mais souvent il ne peut pas.
Une forme particulièrement courante de ceci est où
Funky
est en fait unstd::vector
ou similaire.la source
La plupart des compilateurs ne font aucun type d'optimisation dans une version de débogage.
Si vous utilisez VC, essayez une version de version avec les informations PDB activées - cela vous permettra de suivre l'application optimisée et vous devriez, espérons-le, voir ce que vous voulez alors. Notez, cependant, que le débogage et le traçage d'une version optimisée vous feront voyager partout, et souvent vous ne pouvez pas inspecter directement les variables car elles ne finissent que dans des registres ou sont entièrement optimisées. C'est une expérience "intéressante" ...
la source
Comme Greg le mentionne, les compilateurs ne le feront pas en mode débogage. Il est normal que les versions de débogage soient plus lentes qu'une génération de prod, mais elles ne devraient pas planter plus souvent: et si vous dépendez d'une optimisation des appels de fin, ils peuvent faire exactement cela. Pour cette raison, il est souvent préférable de réécrire l'appel de fin comme une boucle normale. :-(
la source