Me parece que funcionaría perfectamente bien para hacer una optimización de recursión de cola tanto en C como en C ++, aunque durante la depuración nunca parece ver una pila de cuadros que indique esta optimización. Eso es bastante bueno, porque la pila me dice cuán profunda es la recursión. Sin embargo, la optimización también sería agradable.
¿Algún compilador de C ++ hace esta optimización? ¿Por qué? Por qué no?
¿Cómo hago para decirle al compilador que lo haga?
- Para MSVC:
/O2
o/Ox
- Para CCG:
-O2
o-O3
¿Qué tal verificar si el compilador ha hecho esto en cierto caso?
- Para MSVC, habilite la salida PDB para poder rastrear el código, luego inspeccione el código
- Para GCC ..?
Todavía tomaría sugerencias sobre cómo determinar si una determinada función está optimizada de esta manera por el compilador (aunque me parece tranquilizador que Konrad me diga que asuma)
Siempre es posible verificar si el compilador hace esto haciendo una recursión infinita y verificando si resulta en un bucle infinito o un desbordamiento de pila (hice esto con GCC y descubrí que -O2
es suficiente), pero quiero ser capaz de verificar una determinada función que sé que terminará de todos modos. Me encantaría tener una manera fácil de verificar esto :)
Después de algunas pruebas, descubrí que los destructores arruinan la posibilidad de hacer esta optimización. A veces puede valer la pena cambiar el alcance de ciertas variables y temporales para asegurarse de que se salgan del alcance antes de que comience la declaración de retorno.
Si algún destructor necesita ejecutarse después de la llamada de cola, la optimización de la llamada de cola no se puede hacer.
fuente
gcc
tiene una opción más estrecha-foptimize-sibling-calls
para "optimizar las llamadas recursivas entre hermanos y cola". Esta opción (de acuerdo congcc(1)
las páginas de manual para las versiones 4.4, 4.7 y 4.8 de orientación varias plataformas) está activado en niveles-O2
,-O3
,-Os
.gcc 4.3.2 integra completamente esta función (
atoi()
implementación trivial / trivial ) enmain()
. El nivel de optimización es-O1
. Noto que si juego con él (incluso cambiándolo destatic
aextern
, la recursión de la cola desaparece bastante rápido, por lo que no dependería de ello para la corrección del programa.fuente
extern
método podría estar en línea entonces.-O1
hay ninguna inlining y no la optimización de la cola de recursión . Tienes que usar-O2
para eso (bueno, en 4.2.x, que es bastante antiguo ahora, todavía no estará en línea). Por cierto, también vale la pena agregar que gcc puede optimizar la recursividad incluso cuando no es estrictamente una cola (como factorial sin acumulador).Además de lo obvio (los compiladores no hacen este tipo de optimización a menos que usted lo solicite), hay una complejidad sobre la optimización de llamadas de cola en C ++: destructores.
Dado algo como:
El compilador no puede (en general) optimizar la cola porque necesita llamar al destructor
cls
después de que la llamada recursiva regrese.A veces, el compilador puede ver que el destructor no tiene efectos secundarios visibles externamente (por lo que puede hacerse temprano), pero a menudo no puede.
Una forma particularmente común de esto es donde
Funky
es realmente unastd::vector
o similar.fuente
La mayoría de los compiladores no hacen ningún tipo de optimización en una compilación de depuración.
Si usa VC, intente una versión de lanzamiento con la información de PDB activada; esto le permitirá rastrear la aplicación optimizada y, con suerte, debería ver lo que quiere en ese momento. Sin embargo, tenga en cuenta que depurar y rastrear una compilación optimizada lo impulsará por todas partes y, a menudo, no puede inspeccionar las variables directamente, ya que solo terminan en registros o se optimizan por completo. Es una experiencia "interesante" ...
fuente
Como Greg menciona, los compiladores no lo harán en modo de depuración. Está bien que las compilaciones de depuración sean más lentas que una compilación de productos, pero no deberían bloquearse más a menudo: y si depende de una optimización de llamada de cola, pueden hacer exactamente eso. Debido a esto, a menudo es mejor reescribir la llamada de cola como un bucle normal. :-(
fuente