sintaxis resueltos principiantes parametros para funciones ejercicios ejemplos dev con comandos codigos c++ optimization compiler-construction call

resueltos - ¿Los compiladores modernos de C++ son capaces de evitar llamar a una función const dos veces bajo ciertas condiciones?



funciones en dev c++ (5)

GCC tiene el attribute pure (usado como __attribute__((pure)) ) para funciones que le dice al compilador que las llamadas redundantes pueden eliminarse. Se usa, por ejemplo, en strlen .

No conozco ningún compilador que lo haga de forma automática, especialmente si se tiene en cuenta que las funciones que se invocan pueden no estar disponibles en formato fuente y los formatos de archivo de objeto no contienen metadatos sobre si una función es pura o no.

Por ejemplo, si tengo este código:

class SomeDataProcessor { public: bool calc(const SomeData & d1, const SomeData & d2) const; private: //Some non-mutable, non-static member variables } SomeDataProcessor sdp; SomeData data1; SomeData data2; someObscureFunction(sdp.calc(data1, data2), sdp.calc(data1, data2));

Consideremos el código potencialmente equivalente:

bool b = sdp.calc(data1, data2); someObscureFunction(b,b);

Para que esto sea válido, la función calc() debe cumplir algunos requisitos, y para el ejemplo, llamo a la propiedad _pure_const_formula_

Un _pure_const_formula_ :

  • No cambia ningún miembro, estado de variable estático o global
  • Llamar solo a _pure_const_formula_ funciones _pure_const_formula_
  • Tal vez algunas otras condiciones que no tengo en mente

Por ejemplo, llamar a un generador de números aleatorios no cumpliría estos requisitos.

¿Se permite al compilador reemplazar el primer código con el segundo, incluso si necesita cavar recursivamente en las funciones llamadas? ¿Los compiladores modernos pueden hacer esto?


No, dado el código mostrado, el compilador no puede garantizar que la optimización propuesta no tenga diferencias observables, y ningún compilador moderno podrá optimizar la segunda llamada a la función.

Un ejemplo muy simple: este método de clase podría usar un generador de números aleatorios y guardar el resultado en un búfer privado, que alguna otra parte del código lee más adelante. Obviamente, eliminar una llamada de función ahora da como resultado que se coloquen menos valores generados aleatoriamente en ese búfer.

En otras palabras, el hecho de que un método de clase sea const no significa que no tenga efectos secundarios observables cuando se lo llama.


No, el compilador no puede hacer eso en este caso. La const solo significa que no cambia el estado del objeto al que pertenece el método. Sin embargo, invocar este método varias veces con los mismos parámetros de entrada puede dar resultados diferentes. Por ejemplo, piense en un método que produce un resultado aleatorio.


Sí, los compiladores de C modernos pueden eludir llamadas a funciones redundantes si y solo si pueden demostrar que tal optimización se comporta como si se siguiera la semántica del programa original. Por ejemplo, eso significa que podrían eliminar múltiples llamadas a la misma función con los mismos argumentos, si la función no tiene efectos secundarios y si su valor de retorno depende únicamente de los argumentos.

Ahora, preguntaste específicamente sobre const : esto es más útil para el desarrollador y no para el codificador. Una función const es un indicio de que el método no modifica el objeto al que se llama, y ​​los argumentos const son indicios de que los argumentos no se modifican. Sin embargo, la función puede (legalmente 1 ) descartar la const -ness de this puntero o de sus argumentos. Entonces el compilador no puede confiar en eso.

Además, incluso si los objetos const pasados ​​a una función realmente nunca se modificaron dentro de esa función, y las funciones const nunca modificaron el objeto receptor, el método podría basarse fácilmente en datos globales mutables (y podrían mutar tales datos). Considere, por ejemplo, una función que devuelve la hora actual o que incrementa un contador global.

Entonces las declaraciones de const ayudan al programador, no al compilador 2 .

Sin embargo, el compilador podría usar otros trucos para demostrar que las llamadas son redundantes:

  • La función puede estar en la misma unidad de compilación que la persona que llama, lo que permite al compilador inspeccionarla y determinar exactamente en qué se basa. La última forma de esto es resumir: el cuerpo de la función puede moverse al llamador, en cuyo punto el optimizador puede eliminar el código redundante de llamadas posteriores (hasta incluir todo el código de esas llamadas por completo y quizás todo o el puerto de la llamada original) también).
  • La cadena de herramientas puede usar algún tipo de optimización de tiempo de enlace, que efectivamente permite el tipo de análisis descrito en el punto anterior, incluso para las funciones y las personas que llaman en diferentes unidades de compilación. Esto podría permitir esta optimización para cualquier código presente cuando se está generando el ejecutable final.
  • El compilador puede permitir al usuario anotar una función con un atributo que informa al compilador que puede tratar la función como que no tiene efectos secundarios. Por ejemplo, gcc proporciona los atributos de función pure y const que informan a gcc que las funciones no tienen efectos secundarios, y dependen solo de sus parámetros (y en variables globales, en el caso de pure ).

1 Usualmente, siempre y cuando el objeto no se haya definido originalmente como const .

2 Hay un sentido en el que las definiciones const ayudan al compilador: pueden poner objetos globales definidos como const en una sección de solo lectura del ejecutable (si tal característica existe) y también combinar esos objetos cuando son iguales (por ej. , constantes de cuerda idénticas).


Si, absolutamente.

Los compiladores hacen esto todo el tiempo, y más .

Por ejemplo, si todas sus funciones fueran devueltas como true , y su definición fuera visible para el compilador en el callsite, la llamada a toda la función probablemente sería eliminada, lo que resultaría en solo:

someObscureFunction(true, true);

Un programa para el cual el compilador tiene suficiente información puede ser "optimizado" desde una cadena de tareas bastante compleja hasta quizás una o dos instrucciones. Ahora, en realidad, operar en variables miembro está llevando al optimizador a su límite hasta cierto punto, pero si las variables son private , se les da un valor inicial conocido y no están mutadas por ninguna otra función miembro, no veo por qué un compilador no podría simplemente alinear su valor conocido si quisiera. Los compiladores son muy, muy inteligentes.

La gente piensa que un programa compilado es un mapeo uno a uno de líneas en su código fuente, pero esto casi nunca es verdad. Todo el propósito de C ++ es que es una abstracción de lo que realmente va a hacer su computadora cuando ejecuta su programa.