2010-03-15 9 views
18

Digamos que tengo una función donde el parámetro se pasa por valor en lugar de const-reference. Además, supongamos que solo se usa el valor dentro de la función, es decir, que la función no intenta modificarlo. En ese caso, ¿el compilador podrá darse cuenta de que puede pasar el valor por const-reference (por razones de rendimiento) y generar el código en consecuencia? ¿Hay algún compilador que haga eso?¿El compilador optimiza los parámetros de función pasados ​​por valor?

+1

Tenga en cuenta que generalmente el * compilador * solo considera una TU a la vez. En la práctica, las optimizaciones que implican que el llamante haga algo diferente, en función de lo que sucede en el destinatario, solo funcionan si la definición de la función está disponible en la TU de la persona que llama, y ​​/ o con la optimización del tiempo de enlace. –

+0

Pregunta relacionada: http://stackoverflow.com/questions/2043974 –

Respuesta

14

Si pasa una variable en lugar de una temporal, el compilador no puede optimizar la copia si el constructor de copia hace algo que notaría al ejecutar el programa ("comportamiento observable": entradas/salidas, o cambio de variables volátiles).

Aparte de eso, el compilador es libre de hacer todo lo que quiera (solo tiene que parecerse al comportamiento observable como-si no se hubiera optimizado en absoluto).

Solo cuando el argumento es un valor r (más temporal), el compilador puede optimizar la copia al parámetro de valor por valor aunque el constructor de la copia tenga efectos colaterales observables.

+0

Um, ¿no está copiando exento de la regla de si? Pensé que copiar era lo único que el compilador podía eliminar sin preocuparse por las consecuencias. – sbi

+0

Creo que el compilador no necesita garantizar que el constructor de copia no tenga un "comportamiento observable", ya que esa es la misma premisa por la cual el compilador puede elide realizar copias de temporarios. –

+2

@sbi copia está exenta si copia desde un valor r. Si copia de un lvalue, no lo es. Si pasa un valor r y el compilador ingresa el código de la función llamada, puede optimizar todo lo que quiera (de hecho, he visto que GCC optimiza cientos de líneas de ensamblaje con tres o cuatro llamadas anidadas en solo dos o tres líneas) . Ver 12.8/15 en la especificación C++ 03. –

7

Solo si la función no se exporta, existe la posibilidad de que el compilador convierta call-by-reference en call-by-value (o viceversa).

De lo contrario, debido a la convención de llamadas, la función debe mantener la semántica call-by-value/reference.

+2

Pero las copias en línea de esta pueden, por supuesto, optimizarse, aunque la versión externamente visible de la función no lo esté. –

-1

Este post es una excelente referencia a este tipo de optimización: http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/

+0

Creo que le falta el sentido del artículo (al menos en el contexto de esta pregunta). En ese artículo, se hará una copia de una manera u otra, y * se modificará *. – UncleBens

+0

UncleBens: Veo lo que quiere decir, pero pensé que la publicación del blog arroja algo de luz sobre el tipo de optimización que un compilador es capaz de hacer, por lo que sentí que no estaba completamente fuera de tema. Piense en el comentario "¿significa esto que podemos eliminar completa y definitivamente el viejo operador de referencia y copia paso a paso?" A lo que D. Abrahams responde: "¡En realidad, sí! Volcarlo ayer. " – Francesco

0

Con todas las optimizaciones que la respuesta es generalmente "tal vez". La única manera de comprobar es examinar el conjunto de salida y ver lo que realmente está haciendo. Si el estándar lo permite, ya sea que realmente suceda o no depende de los caprichos del compilador. No debe confiar en que esto ocurra porque un cambio arbitrario en cualquier parte de su base de código puede cambiar la heurística utilizada por el optimizador, lo que podría hacer que deje de realizar una determinada optimización.

Juega seguro: codifícalo como te propones, pasa por referencia si eso es lo que quieres. Sin embargo, si está escribiendo código de plantilla que podría funcionar en tipos de cualquier tamaño, la elección no es tan clara. Personalmente, estaría del lado de pasar por la referencia de referencia - el compilador podría también realizar una optimización diferente, donde un tipo pequeño que puede caber dentro del tamaño de una referencia se pasa por valor, en lugar de por referencia constante. Pero, de nuevo, podría suceder, puede que no.

1

No estoy al tanto de ninguna garantía general de que esto se haga, pero si la función llamada está en línea, esto permitirá al compilador ver que se está realizando una copia innecesaria, y si el nivel de optimización es lo suficientemente alto, la operación de copia sería eliminada. GCC puede hacer esto al menos.

Es posible que desee pensar si la clase de este valor de parámetro tiene un constructor de copia o no. Si no lo hace, entonces la diferencia de rendimiento entre pass-by-value y pass-by-const-ref es probablemente insignificante.

Por otro lado, si la clase tiene un constructor de copia que hace cosas, entonces la optimización que está esperando probablemente no ocurra porque el compilador no puede eliminar la llamada al constructor; no puede saber que los efectos secundarios del constructor no son importantes para ti.

Puede obtener más respuestas útiles si dice cuál es la clase del parámetro, o si es una clase personalizada, describe qué campos tiene y si tiene un constructor de copia.

Cuestiones relacionadas