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



performance design (4)

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).

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.


Answer #1

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 &)


Answer #2
  • 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.


Answer #3

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).





design