2008-10-17 23 views
48

He leído todos los consejos sobre const-correctness en C++ y eso es importante (en parte) porque ayuda al compilador a optimizar su código. Lo que nunca he visto es una buena explicación sobre cómo el compilador usa esta información para optimizar el código, ni siquiera los buenos libros continúan explicando lo que sucede detrás de las cortinas.Constantes y optimización del compilador en C++

Por ejemplo, cómo el compilador optimiza un método que se declara const frente a uno que no es, pero debería ser. ¿Qué sucede cuando introduces variables mutables? ¿Afectan estas optimizaciones de los métodos const?

Respuesta

35

métodos indiferencia de Let y mirar sólo a const objetos; el compilador tiene muchas más oportunidades para la optimización aquí.const Si un objeto se declara, entonces (ISO/IEC 14882: 2003 7.1.5.1 (4)):

excepto que cualquier miembro de la clase declaró mutable (7.1.1) se puede modificar, cualquier intento de modifique un objeto const durante su vida útil (3.8) resultados en comportamiento indefinido.

Permite ignorar objetos que pueden tener miembros mutables: el compilador puede suponer que el objeto no se modificará, por lo tanto, puede producir optimizaciones significativas. Estas optimizaciones pueden incluir cosas como:

  • que incorporan el valor del objeto directamente en los códigos operacionales máquinas
  • eliminación completa de código que no se puede alcanzar debido a que el objeto constante se utiliza en una expresión condicional que se conoce en tiempo de compilación
  • tiempo
  • bucle desenrollar si el objeto constante es controlar el número de iteraciones de un bucle

Tenga en cuenta que esto sólo se aplica si el objeto real es const - no se aplica a los objetos que se accede º referencias o puntos de referencia difíciles porque esas rutas de acceso pueden conducir a objetos que no son const (incluso está bien definido para cambiar objetos a través de punteros/referencias siempre que el objeto real no sea const y se descarte la constness del acceso camino al objeto).

En la práctica, no creo que haya compiladores que realicen optimizaciones significativas para todo tipo de objetos const. pero para los objetos que son tipos primitivos (ints, chars, etc.) creo que los compiladores pueden ser bastante agresivos al optimizar el uso de esos elementos.

+0

¿significa que es ilegal eliminar la constness por 'const_cast' para cualquier cosa excepto los tipos primitivos o los objetos const con miembros mutables? –

+2

@AndyT: Sí lo es. Se le permite 'const_cast' alejar la constness solo para los objetos que no son const en primer lugar. –

+6

@AlexandreC. no puedes 'const_cast' alejar la consistencia de cualquier objeto. Pero intentar modificarlo es un comportamiento indefinido. El reparto en sí siempre está bien. – Simple

6

handwaving comienza

Esencialmente, cuanto más temprano se fija los datos, más el compilador puede mover alrededor de la asignación real de los datos, garantizando que la tubería no se cala a cabo

final Onda

3

No optimiza la función que se declara const.

Puede optimizar las funciones que llaman a la función que se declara const.

void someType::somefunc(); 

void MyFunc() 
{ 
    someType A(4); // 
    Fling(A.m_val); 
    A.someFunc(); 
    Flong(A.m_val); 
} 

Aquí para llamar a Fling, el valv A.m_val tuvo que cargarse en un registro de la CPU. Si algunaFunc() no es const, el valor debería volver a cargarse antes de llamar a Flong(). Si algunaFunc es const, entonces podemos llamar a Flong con el valor que todavía está en el registro.

+1

No creo que const ayude con la optimización en absoluto. A.someFunc() podría fácilmente hacer const_cast (esto) -> m_val = 42; o cualquier cantidad de otras cosas que cambiarían m_val (por ejemplo, si hay un puntero no const para A en una variable global, algúnFunc podría cambiarlo) – Qwertie

+3

El compilador puede suponer que no descartará const; Hágalo bajo su propio riesgo. Y, como A vive completamente dentro de MyFunc(), el compilador puede rastrear si hay un puntero global al mismo. (En este ejemplo, no puede haber) –

+2

No estoy seguro de que esta respuesta (y comentario) sea correcta. Por lo que yo sé, es completamente legal descartar constness y modificar un objeto, siempre que no sea un objeto const. En su ejemplo, A no es const, por lo que 'somefunc' (que no se declara const, btw) puede rechazar la constness en' this' y modificar el objeto actual. Sin embargo, si A se definió como 'const someType A (4)', entonces modificarlo descartando constness arrojaría un comportamiento indefinido. En consecuencia, no creo que el compilador pueda optimizar nada en el ejemplo que proporcionó. –

3

La principal razón para tener métodos como const es para la corrección constante, no para su posible optimización compilación del método en sí.

Si variables son const pueden (en teoría) optimizarse. Pero solo el alcance puede ser visto por el compilador. Después de todo, el compilador debe permitir que se modifiquen con un const_cast en otro lugar.

5

Meh. Const-correctness es más una cosa de estilo/comprobación de errores que una optimización. Un compilador de optimización completo seguirá el uso de variables y puede detectar cuándo una variable es const o no efectiva.

Agregado a eso, el compilador no puede confiar en que diga la verdad: podría estar descartando la const dentro de una función de biblioteca que desconoce.

Así que sí, const-correctness es algo digno de apuntar, pero no le dice nada al compilador que no se dará cuenta, asumiendo un buen compilador de optimización.

1

Me sorprendería si el optimizador realmente hace mucho inventario en una declaración de const. Hay un montón de código que terminará alejando la const-ness, sería un optimizador muy imprudente que se basó en la declaración del programador para asumir cuando el estado puede cambiar.

+1

Sería un programador muy irreflexivo deshacerse de la constness. ¿Qué estaría pensando ella, "naaah, la documentación realmente no significa que sea inmutable. No se aplica a _me_"? – gnud

+0

@gnud: irrelevante: el compilador no puede suponer que el programador no lo está haciendo. –

+2

@Mike F: Extremadamente relevante, el compilador PUEDE asumir que el programador no lo está haciendo. El estándar establece (7.1.6.1/4) que: "Excepto que cualquier miembro de clase declarado mutable puede modificarse, cualquier intento de modificar un objeto const durante su vida útil da como resultado un comportamiento indefinido". –

54

Creo que la palabra clave const se introdujo principalmente para la comprobación de compilación de la semántica del programa, no para la optimización.

Herb Sutter, en el GotW #81 article, explica muy bien por qué el compilador no puede optimizar nada al pasar parámetros por referencia constante, o al declarar el valor de retorno constante.La razón es que el compilador no tiene forma de asegurarse de que el objeto al que se hace referencia no cambiará, incluso si se declara const: uno podría usar un const_cast, o algún otro código puede tener una referencia no constante en el mismo objeto.

Sin embargo, citando el artículo de Herb Sutter:

No es [sólo] un caso en el que dice "const" en realidad puede significar algo, y que es cuando los objetos están hechos const en el punto de que son definido. En ese caso , el compilador puede a menudo colocar con éxito tales objetos "realmente const" en la memoria de solo lectura [...].

Hay mucho más en este artículo, por lo que le animo a leerlo: después de eso, tendrá una mejor comprensión de la optimización constante.

0

El punto más obvio donde const es una optimización directa es al pasar argumentos a una función. A menudo es importante asegurarse de que la función no modifica los datos de modo que las únicas opciones reales para la firma de la función son los siguientes:

void f(Type dont_modify); // or 
void f(Type const& dont_modify); 

Por supuesto, la verdadera magia aquí está pasando una referencia en lugar de crear un (caro) copia del objeto. Pero si la referencia no estuviera marcada como const, esto debilitaría la semántica de esta función y tendría efectos negativos (como dificultar el rastreo de errores). Por lo tanto, const permite una optimización aquí.

/EDITAR: en realidad, un buen compilador puede analizar el flujo de control de la función, determinar que no modifique el argumento y hacer la optimización (pasando una referencia en lugar de una copia). const aquí es meramente una ayuda para el compilador. Sin embargo, dado que C++ tiene una semántica bastante complicada y dicho análisis de flujo de control puede ser muy costoso para grandes funciones, probablemente no deberíamos confiar en los compiladores para esto. ¿Alguien tiene datos para respaldarme/probar que estoy equivocado?

/EDIT2: y sí, tan pronto como entran en juego los constructores de copia personalizada, se vuelve aún más complicado porque desafortunadamente los compiladores no pueden omitir llamarlos en esta situación.

+1

O bien sus herramientas de compilación necesitan optimización de tiempo de enlace, o su constructor de copia (y posiblemente destructor) deben estar visibles para el compilador en el sitio de llamada. De lo contrario, el compilador no podrá optimizar una copia. – Tom

0

Este código,

class Test 
{ 
public: 
    Test (int value) : m_value (value) 
    { 
    } 

    void SetValue (int value) const 
    { 
    const_cast <Test&>(*this).MySetValue (value); 
    } 

    int Value() const 
    { 
    return m_value; 
    } 

private: 
    void MySetValue (int value) 
    { 
    m_value = value; 
    } 

    int 
    m_value; 
}; 

void modify (const Test &test, int value) 
{ 
    test.SetValue (value); 
} 

void main() 
{ 
    const Test 
    test (100); 

    cout << test.Value() << endl; 
    modify (test, 50); 
    cout << test.Value() << endl; 
} 

salidas:

100 
50 

que significa que el const declarados objeto ha sido modificado de una función miembro const. La presencia de const_cast (y la palabra clave mutable) en el lenguaje C++ significa que la palabra clave const no puede ayudar al compilador a generar código optimizado. Y como señalé en mis publicaciones anteriores, incluso puede producir resultados inesperados.

Como regla general:

const = optimización

De hecho, este es un C legal ++ modificador:

volatile const 
+5

Usted no entiende 'const'. – curiousguy

+2

a pesar de que estoy de acuerdo en que la optimización se promociona con frecuencia, pero nunca se ha demostrado que yo haya visto, esta publicación no es una evidencia a favor de eso. estás bombardeando deliberadamente al compilador con exigencias de que debe permitirte dispararte en el pie, e invocar a UB en el proceso, y luego concluir que 'const' está roto. no, tu código está roto. 'void main' es una buena cereza en la parte superior de esta prueba que. –

-1

const ayuda a los compiladores a optimizar principalmente porque te hace escribir código optimizable. A menos que arroje const_cast.

+1

Desafortunadamente, esto no es cierto. El compilador debe suponer que const_cast y las partes internas mutables existirán en cualquier otro lugar, a menos que pueda ver todo el código en una sola pasada (código de solo cabecera). – Tom

2

Todas estas son respuestas verdaderas, pero las respuestas y la pregunta parecen presumir una cosa: la optimización del compilador realmente importa.

No es sólo un tipo de código en materia de optimización del compilador, es decir en el código que es

  • un bucle interior apretada,
  • en el código que se compila, en oposición a una biblioteca 3 ª parte ,
  • no contiene los métodos o funciones llamadas (incluso los ocultos),
  • , donde el contador de programa pasa una fracción apreciable de su tiempo

Si el otro 99% del código está optimizado hasta el grado Nth, no hará una gran diferencia, porque solo importa en el código donde el contador del programa realmente gasta tiempo (que puede encontrar mediante muestreo).

1

const-correctness también es útil como documentación. Si una función o parámetro está listado como const, no necesito preocuparme por el cambio de valor desde mi código (a menos que alguien más en el equipo esté siendo muy malo). Sin embargo, no estoy seguro de que realmente valga la pena si no estuviera integrado en la biblioteca.

Cuestiones relacionadas