trucos tips programar programacion programa peephole para optimizar optimizacion mejorar consejos con como codigo c++ c const compiler-optimization

c++ - programacion - tips para programar en c



¿Qué tipo de optimización ofrece const en C/C++? (5)

Parámetros de la función:

const no es significativo para la memoria referenciada. Es como atar una mano a la espalda del optimizador.

Suponga que llama a otra función (por ejemplo, void bar() ) en foo que no tiene una definición visible. El optimizador tendrá una restricción porque no tiene forma de saber si bar ha modificado o no el parámetro de función pasado a foo (por ejemplo, a través del acceso a la memoria global). El potencial para modificar la memoria externamente y el alias introducen restricciones significativas para los optimizadores en esta área.

Aunque no preguntó, los valores const para los parámetros de la función permiten optimizaciones porque el optimizador tiene garantizado un objeto const . Por supuesto, el costo de copiar ese parámetro puede ser mucho mayor que los beneficios del optimizador.

Ver: http://www.gotw.ca/gotw/081.htm

Declaraciones variables: const int i = 1234

Esto depende de dónde se declara, cuándo se crea y el tipo. Esta categoría es en gran parte donde existen optimizaciones const . No está definido para modificar un objeto const o una constante conocida, por lo que el compilador puede realizar algunas optimizaciones; asume que no invocas comportamientos indefinidos y eso introduce algunas garantías.

const int A(10); foo(A); // compiler can assume A''s not been modified by foo

Obviamente, un optimizador también puede identificar variables que no cambian:

for (int i(0), n(10); i < n; ++i) { // << n is not const std::cout << i << '' ''; }

Declaraciones de funciones: const char* foo()

Insignificante. La memoria referenciada puede modificarse externamente. Si la variable referenciada devuelta por foo es visible, entonces un optimizador podría hacer una optimización, pero eso no tiene nada que ver con la presencia / ausencia de const en el tipo de retorno de la función.

De nuevo, un valor u objeto const es diferente:

extern const char foo[];

Sé que, siempre que sea posible, debe usar la palabra clave const cuando pase parámetros por referencia o por puntero por razones de legibilidad. ¿Hay alguna optimización que el compilador pueda hacer si especifico que un argumento es constante?

Podría haber algunos casos:

Parámetros de la función:

Referencia constante:

void foo(const SomeClass& obj)

Objeto constante SomeClass:

void foo(const SomeClass* pObj)

Y puntero constante a SomeClass:

void foo(SomeClass* const pObj)

Declaraciones variables:

const int i = 1234

Declaraciones de funciones:

const char* foo()

¿Qué tipo de optimizaciones del compilador ofrece cada una (si hay alguna)?


Antes de dar una respuesta, quiero enfatizar que la razón para usar o no usar const realmente debería ser la corrección del programa y la claridad para otros desarrolladores más que para las optimizaciones del compilador; es decir, hacer un parámetro const documenta que el método no modificará ese parámetro, y hacer que una función miembro const documente que ese miembro no modificará el objeto del cual es miembro (al menos no de una manera que cambie lógicamente la salida desde cualquier otra función miembro const). Hacer esto, por ejemplo, permite a los desarrolladores evitar hacer copias innecesarias de objetos (porque no tienen que preocuparse de que el original sea destruido o modificado) o evitar la sincronización innecesaria de hilos (por ejemplo, sabiendo que todos los hilos simplemente leen y hacen no mutar el objeto en cuestión).

En términos de optimizaciones que un compilador podría hacer, al menos en teoría, aunque en un modo de optimización que le permita hacer ciertas suposiciones no estándar que podrían romper el código estándar de C ++, considere:

for (int i = 0; i < obj.length(); ++i) { f(obj); }

Suponga que la función de length está marcada como const pero en realidad es una operación costosa (digamos que realmente funciona en tiempo O (n) en lugar de tiempo O (1)). Si la función f toma su parámetro por referencia const , entonces el compilador podría optimizar este bucle para:

int cached_length = obj.length(); for (int i = 0; i < cached_length; ++i) { f(obj); }

... porque el hecho de que la función f no modifique el parámetro garantiza que la función de length debería devolver los mismos valores cada vez dado que el objeto no ha cambiado. Sin embargo, si se declara que f toma el parámetro mediante una referencia mutable, entonces la length necesitaría ser recalculada en cada iteración del ciclo, ya que f podría haber modificado el objeto de una manera para producir un cambio en el valor.

Como se señaló en los comentarios, esto supone una serie de advertencias adicionales y solo sería posible al invocar al compilador en un modo no estándar que le permita hacer suposiciones adicionales (como que los métodos const son estrictamente una función de sus entradas y que las optimizaciones pueden suponer que el código nunca usará const_cast para convertir un parámetro de referencia const en una referencia mutable).


Los efectos exactos de const difieren para cada contexto donde se usa. Si se usa const mientras se declara una variable, es físicamente constante y reside de manera potente en la memoria de solo lectura.

const int x = 123;

Intentar deshacerse de la constancia es un comportamiento indefinido:

Aunque const_cast puede eliminar la constidad o la volatilidad de cualquier puntero o referencia, usar el puntero o referencia resultante para escribir en un objeto que se declaró const o para acceder a un objeto que se declaró volátil invoca un comportamiento indefinido. cppreference/const_cast

Entonces, en este caso, el compilador puede suponer que el valor de x siempre es 123 . Esto abre un potencial de optimización (propagación constante)

Para las funciones es un asunto diferente. Suponer:

void doFancyStuff(const MyObject& o);

nuestra función doFancyStuff puede hacer cualquiera de las siguientes cosas con o .

  1. No modificar el objeto.
  2. desechar la constidad, luego modificar el objeto
  3. modificar un miembro de datos mutable de MyObject

Tenga en cuenta que si llama a nuestra función con una instancia de MyObject que se declaró como constante, invocará un comportamiento indefinido con # 2.

Pregunta del gurú: ¿invocará el siguiente comportamiento indefinido?

const int x = 1; auto lam = [x]() mutable {const_cast<int&>(x) = 2;}; lam();


[Los lectores deben tener en cuenta que la mayoría de esta publicación se ha extraído de un artículo de Herb Sutter - http://www.gotw.ca/gotw/081.htm - sin atribución del OP.]

CASO 1:-

Cuando declaras una constante en tu programa,

int const x = 2;

El compilador puede optimizar esta constante al no proporcionar almacenamiento a esta variable, sino agregarla en la tabla de símbolos. Por lo tanto, la lectura posterior solo necesita una dirección indirecta en la tabla de símbolos en lugar de instrucciones para recuperar el valor de la memoria.

NOTA: - Si haces algo como lo siguiente: -

const int x = 1; const int* y = &x;

Entonces esto obligaría al compilador a asignar espacio para ''x'' . Entonces, ese grado de optimización no es posible para este caso.

En términos de parámetros de función, const significa que el parámetro no se modifica en la función. Hasta donde sé, no hay una ganancia sustancial de rendimiento por usar const sino que es un medio para garantizar la corrección.

CASO_2: -

"¿Declarar el parámetro y / o el valor de retorno como constante ayuda al compilador a generar un código más óptimo?"

const Y& f( const X& x ) { // ... do something with x and find a Y object ... return someY; }

Ques => ¿Qué podría hacer mejor el compilador?

=> ¿Podría evitar una copia del parámetro o el valor de retorno?

No, ya que el argumento ya se pasa por referencia.

=> ¿Podría poner una copia de x o someY en la memoria de solo lectura?

No, ya que tanto x como someY viven fuera de su alcance y provienen y / o se entregan al mundo exterior. Incluso si algoY se asigna dinámicamente sobre la marcha dentro de f () mismo, él y su propiedad se entregan a la persona que llama.

Ques => ¿Qué pasa con las posibles optimizaciones de código que aparecen dentro del cuerpo de f ()? Debido a la constante, ¿podría el compilador mejorar de alguna manera el código que genera para el cuerpo de f ()?

Incluso cuando llama a una función miembro const, el compilador no puede suponer que los bits del objeto x o del objeto someY no se cambiarán. Además, hay problemas adicionales (a menos que el compilador realice una optimización global): el compilador también puede no estar seguro de que ningún otro código pueda tener una referencia no constante que alias el mismo objeto que x y / o someY, y si alguno las referencias no constantes al mismo objeto pueden usarse de manera incidental durante la ejecución de f (); y el compilador puede que ni siquiera sepa si los objetos reales, a los que x y someY son meras referencias, se declararon realmente const en primer lugar.

CASO_3: -

void f( const Z z ) { // ... }

Ques => ¿Habrá alguna optimización en esto?

Sí, porque el compilador sabe que z realmente es un objeto constante, podría realizar algunas optimizaciones útiles incluso sin un análisis global. Por ejemplo, si el cuerpo de f () contiene una llamada como g (& z), el compilador puede estar seguro de que las partes no mutables de z no cambian durante la llamada a g ()


SomeClass* const pObj crea un objeto constante de tipo puntero. No existe un método seguro para cambiar dicho objeto, por lo que el compilador puede, por ejemplo, almacenarlo en caché en un registro con solo una lectura de memoria, incluso si se toma su dirección.

Los otros no habilitan ninguna optimización específicamente, aunque el calificador const en el tipo afectará la resolución de sobrecarga y posiblemente resultará en la selección de funciones diferentes y más rápidas.