c++ performance design

c++ - Pasar enteros como referencias constantes en lugar de copiar



performance design (5)

Esta podría ser una pregunta estúpida, pero observo que en un buen número de API, muchas firmas de métodos que toman parámetros enteros que no están destinados a ser modificados se ven así:

void method(int x);

más bien que:

void method(const int &x);

Para mí, parece que ambos funcionarían exactamente igual. (EDITAR: aparentemente no en algunos casos, ver la respuesta de R Samuel Klatchko) En el primero, el valor se copia y, por lo tanto, no puede cambiar el original. En este último, se pasa una referencia constante, por lo que no se puede cambiar el original.

Lo que quiero saber es por qué uno sobre el otro: ¿es porque el rendimiento es básicamente el mismo o incluso mejor con el primero? por ejemplo, pasar un valor de 16 bits o de 32 bits en lugar de una dirección de 32 bits o de 64 bits? Esta fue la única razón lógica que se me ocurrió, solo quiero saber si esto es correcto y, de no ser así, por qué y cuándo preferiría int x sobre const int &x y / o viceversa. Gracias.


Es probable que haya una desestimación muy, muy pequeña para pasar por referencia, ya que, como mínimo, tendrá que producirse una desreferencia para obtener el valor real (a menos que la llamada esté en línea, el compilador no puede simplemente pasar el valor debido a la el hecho de que el sitio de llamada y la función se compilan por separado, y es válido y bien definido para descartar la const para un parámetro pasado que no es realmente const - ver cuáles son los beneficios para pasar tipos integrales por const ref ). Sin embargo, tenga en cuenta que es probable que la "desoptización" sea tan pequeña que sea difícil de medir.

A la mayoría de las personas no les gusta el pass-by-const-ref para los built-ins debido a esto (mucho). Sin embargo, creo que podría ser preferible en algunos casos si desea que el compilador lo ayude a garantizar que el valor no se cambie accidentalmente dentro de la función. No es una gran cosa, pero a veces puede ser útil.


Los enteros generalmente tienen el tamaño de la palabra original del procesador y pueden pasar fácilmente a los registros. Desde esta perspectiva, no hay diferencia entre pasar por valor o pasar por referencia constante.

En caso de duda, imprima la lista del idioma del ensamblador de sus funciones para descubrir cómo el compilador pasa el argumento. Imprima para pasar por valor y pasar por referencia constante.

Además, al pasar por valor, la función puede modificar la copia. Al pasar por referencia constante, la función no puede modificar la variable (está marcada como const).


No es solo el costo de pasar un puntero (que es esencialmente lo que es una referencia), sino también la eliminación de referencias en el cuerpo del método llamado para recuperar el valor subyacente.

Es por eso que virtualmente se garantiza que pasar un int por valor sea más rápido (Además, el compilador puede optimizar y simplemente pasar el int través de los registros del procesador, eliminando la necesidad de insertarlo en la pila).


Para mí, parece que ambos funcionarían exactamente igual.

Depende de exactamente a qué se refiere la referencia. Aquí hay un ejemplo reconocido que cambiaría en función de si pasa una referencia o un valor:

static int global_value = 0; int doit(int x) { ++global_value; return x + 1; } int main() { return doit(global_value); }

Este código se comportará de manera diferente dependiendo de si tiene int doit(int) o int doit(const int &)


  • Dependiendo del conjunto de instrucciones subyacente, un parámetro entero se puede pasar como registro o en la pila. El registro es definitivamente más rápido que el acceso a la memoria, lo que siempre sería necesario en el caso de const refs (considerando arquitecturas tempranas sin caché)

  • No se puede pasar un literal int como una constante int &

  • Los cambios de tipo explícitos te permiten emitir un const int y en * (const int *) abriendo la posibilidad de cambiar el valor de la referencia pasada.