2010-11-10 20 views
12

Esta es una pregunta de eficiencia acerca de las entradas de 64 bits. Suponiendo que no necesito modificar el valor de un parámetro "int", debería pasarlo por valor o referencia.C++ 64 bit int: pasar por referencia o pasar por valor

Suponiendo máquina de 32 bits:

1) de 32 bits int: Yo supongo la respuesta es "paso por valor" como "el paso por referencia" tendrá sobrecarga de las operaciones de búsqueda de memoria adicional.

2) 64 bit int: Si paso por referencia, solo paso la dirección de 32 bits en la pila, pero necesito una búsqueda de memoria adicional. Entonces, ¿cuál de ellos es mejor (referencia o valor)?

¿Qué pasa si la máquina es de 64 bits?

cordiales,

JP

+3

"eficiencia" :(BESO. Pásalo como pasas todos los enteros sangrientos. –

+0

El compilador probablemente lo optimice de todos modos. –

+0

@pst: +1 para comentario divertido. Hombre me reí muy duro. –

Respuesta

10

Pase por valor - definitivamente. Si el sistema es de 64 bits, significa que copia palabras de 64 bits extremadamente rápido.

8

Incluso en una máquina de 64 bits pase por el valor es mejor (con algunas pocas excepciones), ya que se puede pasar como un valor de registro.

+7

Diría * especialmente * en una máquina de 64 bits. – cHao

+0

Así que pasar int de 64 bits "por valor" es más eficiente que pasar int de 64 bits "por referencia" en máquinas de 32 bits o de 64 bits (incluso más en máquinas de 64 bits), ¿verdad? –

+0

Tengo curiosidad por saber las excepciones (eso no está fuera del alcance de la discusión :) –

4

Por razones de argumento, vamos a ignorar el caso trivial de los optimizadores que eliminan las diferencias. Digamos también que está utilizando las convenciones de llamadas Intel de 64 bits de Microsoft (que difieren de las de Linux ABI), luego tiene 4 registros de 64 bits para pasar esos valores antes de que tenga que recurrir a empujarlos a la pila. Eso es claramente mejor.

Para una aplicación de 32 bits, por valor e irían directamente a la pila. La referencia puede, por el contrario, poner un puntero en un registro (de nuevo, se permiten algunos de esos usos de registro antes de recurrir a la pila). Podemos esto de alguna salida de g ++ -O3 -S, llamando f1 (99) por su valor y f2 (101) por referencia const:

void f1(int64_t); 
void f2(const int64_t&); 

int main() 
{ 
    f1(99); 
    f2(101); 
} 

... 

    pushl 0 
    pushl $99 
    call _Z2f1x // by value - pushed two halves to stack 

    leal -8(%ebp), %eax 
    movl %eax, (%esp) 
    movl $101, -8(%ebp) 
    movl $0, -4(%ebp) 
    call _Z2f2RKx // by const& - ugly isn't it!?! 

La función llamada tendríamos entonces para recuperar antes del primer uso (si lo hay) La función llamada es libre de almacenar en caché los valores leídos en los registros, por lo que solo es necesario una vez. Con el enfoque de pila, el valor se puede volver a leer a voluntad, por lo que no es necesario reservar el registro para ese valor. Con el enfoque del puntero, es posible que el puntero o el valor de 64 bits deban guardarse en algún lugar más predecible (por ej., Empujado u otro registro menos útil) si dicho registro debe liberarse momentáneamente para algún otro trabajo, pero el de 64 bits El parámetro int se necesita de nuevo más tarde. En general, es difícil adivinar cuál es más rápido, puede depender de la CPU/uso de registro/optimizador/etc., y no vale la pena intentarlo.

un nodo para el consejo de pst ...

"eficiencia" :(BESO pasarlo cómo se pasa cada dos enteros con sangre -.. Pst

... aunque, a veces se aplica a la plantilla de KISS parámetros y hacer que todos sean const T & aunque algunos caben en los registros ....

7

. Páselos como boost::call_traits<int64_t>::param_type. Esta plantilla captura las mejores prácticas para pasar cualquier tipo de las plataformas compatibles. Por lo tanto, será diferente en plataformas de 32 y 64 bits, pero puede usar el mismo código en todas partes. Incluso funciona nside otras plantillas donde aún no se conoce el tipo exacto.

+10

+1 este es, de lejos, el mejor castigo para las personas preocupadas por optimizar el paso de enteros, que tienen que escribir ese lote. –

+0

Quizás sea cierto que para los datos de 64 bits la diferencia es insignificante. Sin embargo, el espíritu de la pregunta vale la pena. ¿Qué pasa si tengo una estructura de 12 bytes? 16 byte? El comentario de Hans Passant, aunque no puede ser verificado o probado técnicamente, al menos da una indicación en la dirección correcta. –

+0

Por supuesto, es útil saber que para 64 bits uno no necesita preocuparse :). (Aunque nuestro código llamará a este tipo de funciones cientos de millones de veces y se ejecuta durante horas en general. En ese caso, siempre es bueno seguir lo que son "mejores" prácticas). –

1

Use un poco de sentido común,

  1. si el objeto requiere de un complejo constructor de copia, probablemente vale la pena pasar por referencia (diciendo que - un buen montón de objetos de Boost están diseñados para ser pasado por caso valor en lugar de referencia, simplemente porque la implementación interna es bastante trivial) Hay uno impar que realmente no he resuelto, std::string, siempre paso esto por referencia ...

  2. Si tiene la intención de modificar el valor que se pasa, use una referencia

  3. Else, PASS-BY-VALUE!

¿Tiene un cuello de botella de rendimiento particular con argumentos para las funciones? Si no, no pasar demasiado tiempo preocupándose por lo cual es la mejor manera de pasar ...

Optimización por la preocupación de cómo un int se pasa en es como pi ** ing en el mar ...

+0

Me gustaría resolver el rompecabezas: " proxenetismo en el mar " – weberc2

Cuestiones relacionadas