2012-01-31 4 views
15

Tengo un puntero int* p y realizo algunas operaciones en un bucle. No modifico la memoria, solo leo. Si agrego const al puntero (en ambos casos, const int* p y int* const p), ¿puede ayudar a un compilador a optimizar el código?¿Puede la adición de 'const' a un puntero ayudar a la optimización?

Conozco otros méritos de const, como seguridad o auto-documentación, pregunto sobre este caso en particular. Reformulando la pregunta: ¿puede el const dar al compilador alguna información útil (para optimización) alguna vez?

+3

¿De verdad quieres decir 'int const * p'? O 'int * const p'? ¿Qué loop? ¿Qué estás iterando? –

+1

Podrías hacerlo y comparar el código generado: -? – cnicutar

+1

La única manera de determinar esto para una CPU, compilador, sistema operativo, etc. determinado es compararlo, y el resultado solo será válido para esta configuración particular, por supuesto. Me parece una optimización prematura. –

Respuesta

6

Si bien esto es obviamente específico para la implementación, es difícil ver cómo el cambio de un puntero de int* a int const* podría proporcionar alguna información adicional que el compilador de otra forma no hubiera conocido.

En ambos casos, el valor señalado puede cambiar durante la ejecución del ciclo.

Por lo tanto, probablemente no ayudará al compilador a optimizar el código.

+0

Esto es simplemente incorrecto; 'int const *' es equivalente a 'const int *' que no * apunta a la memoria grabable. (Lo que quiere decir es probablemente 'int * const') –

+1

@JoSo: No, esto es correcto. Todo lo que 'int const *' indica es que 'int' no se puede modificar a través de ese puntero en particular. Si el 'int' era originalmente no const, entonces puede ser modificado por otra parte del código, o puede ser modificado por la misma parte del código después de un molde. – Mankarse

+0

Me salió mal la respuesta y no puedo recordar cómo sucedió esto. Lo siento por eso. Peor aún, obviamente no está permitido eliminar un voto (a la baja) a menos que la respuesta sea editada ... :( –

2

Puede ayudar o no puede hacer la diferencia o puede empeorar las cosas. La única manera de saber es probar ambos e inspeccionar el código de la máquina emitida.

Los compiladores modernos son muy inteligentes, por lo que a menudo pueden deducir que la memoria no cambia sin ningún calificador (pueden deducir que muchas otras optimizaciones son posibles sin código escrito de manera más fácil de analizar) pero son bastante complejas y tienen un muchas deficiencias y, a menudo no se puede optimizar todo lo posible en cada oportunidad.

+0

¿Tiene algún ejemplo cuando puede empeorar las cosas? –

+0

@Jakub M .: No es para este caso específico, pero he visto literalmente docenas de casos cuando un compilador no pudo emitir el código óptimo. – sharptooth

+2

* puede empeorar * es una exageración y afirmación demasiado generalizada, a menos que esté justificado con un ejemplo, 'const' no puede hacer ninguna diferencia o * alguna * diferencia, y la diferencia es insignificante para no considerar su uso como un criterio de optimización , solo se debe usar para escribir un código de mantenimiento más correcto. –

3

No. Usar const like that no proporcionará al compilador ninguna información que pueda usarse para la optimización.

Teóricamente, para que sea una ayuda para su compilador, el optimizador debe ser capaz de demostrar que nadie usará const_cast en su puntero const pero no podrá demostrar que la variable nunca se escribió. Tal situación es altamente improbable.

Herb Sutter cubre esto con más profundidad en una de sus columnas Guru of the Week.

+0

Si el compilador * puede * probar toda esa información adicional, ya no necesita la calificación 'const'. incluso entonces, el 'const' no ayudará con la optimización. – Mankarse

+0

@Mankarse: a menos que por alguna razón tonta específica de la implementación, por ejemploun optimizador particular no molesta en hacer el análisis a menos que el puntero esté calificado. Pero sigues siendo correcto en lo que dices, porque con mi argumento * cualquier cosa * puede afectar la optimización: el número de vocales en tus nombres de variable, o si aplica sangría con tabulaciones vs espacios. La única pregunta es cuán plausible es que el optimizador ignore cierta información potencialmente útil en algunas circunstancias, pero no en otras. –

1

Creo que el compilador no puede hacer mucho en su escenario. El hecho de que su puntero declarado como const int * const p no garantiza que la memoria no se pueda cambiar externamente, p. por otro hilo Por lo tanto, el compilador debe generar código que lea el valor de memoria en cada iteración de su ciclo.

Pero si que no van a escribir en la ubicación de memoria y que sabe que ningún otro fragmento de código, a continuación, puede crear una variable local y utilizarlo similar a esto:

const int * p = ... 
... 
int val = *p; 
/* use the value in a loop */ 
for (i = 0; i < BAZILLION; i++) 
{ 
    use_value(val); 
} 

No solo ayuda a los lectores potenciales de su código a ver que el val no se cambia en un bucle, sino que también le da al compilador la posibilidad de optimizar (cargar val en un registro, por ejemplo).

+2

Los compiladores generalmente no consideran otros hilos a menos que agregue específicamente volátiles. Sin embargo, cualquier llamada a función se interpondría en el camino. –

+0

@PerJohansson: probablemente tengas razón. De todos modos, otro hilo fue solo un ejemplo. El efecto secundario de cualquier llamada de función es también un buen ejemplo. Solo quería señalar que cualquier optimización realizada por el compilador debe (y lo hace) preservar la semántica original del código, mientras que la optimización de las lecturas de memoria dentro de un ciclo ciertamente no lo hace, y por lo tanto no se realizará. Pero como no existe una forma legal de cambiar 'val' externamente (fuera del cuerpo de la función), el compilador puede optimizarlo. –

1

El uso de const es, como todos han dicho, poco probable que ayude al compilador a optimizar su ciclo.

Puede, sin embargo, ayudar a optimizar el código fuera de el bucle, o en el sitio de una llamada a un método const-calificado, o a una función que toma argumentos const.

Esto probablemente dependa de si el compilador puede probar que está permitido eliminar cargas redundantes, moverlas o guardar valores calculados en lugar de volver a calcularlos.

La única manera de probar esto sigue siendo perfilar y/o verificar el ensamblaje, pero es ahí donde probablemente debería estar buscando.

1

Usted no dice qué compilador está utilizando. Pero si ambos leen y escriben en la memoria, podrían beneficiarse del uso de "restringir" o similar. El compilador no sabe si los punteros aliasen la misma memoria, por lo que cualquier tienda a menudo obliga a cargar otros valores de nuevo. "restringir" le dice al compilador que no hay aliasing del puntero y puede seguir utilizando los valores cargados antes de una posterior escritura. Otra forma de evitar el problema del aliasing es cargar sus valores en variables locales, luego el compilador no está obligado a volver a cargar después de escribir.

Cuestiones relacionadas