2010-11-10 14 views
12

Questa è una domanda di efficienza su 64 bit int. Supponendo che non sia necessario modificare il valore di un parametro "int", dovrei passarlo per valore o riferimento.C++ 64 bit int: passa per riferimento o passa per valore

Supponendo macchina a 32 bit:

1) 32 bit int: I immagino la risposta è "passaggio per valore" come "pass per riferimento" avrà overhead di ricerca memoria aggiuntiva.

2) int per 64 bit: se passo per riferimento, ho solo passato l'indirizzo a 32 bit nello stack, ma ho bisogno di una ricerca di memoria aggiuntiva. Quindi qual è il migliore (riferimento o valore)?

Cosa succede se la macchina è a 64 bit?

saluti,

JP

+3

"efficienza" :(BACIO, passalo come passi ogni altro intero sanguinoso –

+0

Il compilatore probabilmente lo ottimizzerà comunque –

+0

@pst: +1 per commento divertente uomo ho riso molto duro –

risposta

10

Passaggio di valore - sicuramente. Se il sistema è a 64 bit, significa che copia a 64 bit la parola estremamente velocemente.

8

Anche su un passaggio macchina a 64 bit per valore è migliore (con alcune pochissime eccezioni), perché può essere passato come un valore di registro.

+7

Direi * specialmente * su una macchina a 64 bit. – cHao

+0

Quindi il passaggio di 64-bit int "per valore" è più efficiente del passaggio di 64 bit int "per riferimento" su macchine a 32 bit o 64 bit, (ancor più su macchine a 64 bit), giusto? –

+0

Sono curioso di sapere le eccezioni (non è fuori dal campo di discussione :) –

4

Per ragioni di argomenti, ignoriamo il caso banale degli ottimizzatori che rimuovono le differenze. Diciamo anche che stai usando le convenzioni di chiamata Intel a 64 bit di Microsoft (che differiscono dall'ABI di Linux), quindi hai 4 registri a 64 bit per passare tali valori prima di dover ricorrere a spingerli nello stack. Questo è chiaramente meglio.

Per un'applicazione a 32 bit, in base al valore, andrebbero direttamente nello stack. By-reference può invece mettere un puntatore in un registro (di nuovo, alcuni di questi usi del registro sono consentiti prima di ricorrere allo stack). Siamo in grado di questo in qualche uscita dal g ++ -O3 -S, chiamando f1 (99) per valore e f2 (101) con riferimento 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 funzione chiamata sarebbe poi dovuto recuperare prima del primo utilizzo (se presente). La funzione chiamata è libera di memorizzare nella cache i valori letti nei registri, quindi è necessaria solo una volta. Con l'approccio stack, il valore può essere riletto a piacimento, quindi il registro non deve essere riservato per quel valore. Con l'approccio puntatore, potrebbe essere necessario salvare il puntatore o il valore a 64 bit in qualche luogo più prevedibile (es. Spinto, o un altro registro meno utile) nel caso in cui quel registro debba essere momentaneamente liberato per qualche altro lavoro, ma il 64-bit il parametro int sarà nuovamente necessario in seguito. Tutto sommato, è difficile indovinare quale sia più veloce - potrebbe essere dipendente dalla CPU/registro/ottimizzatore/ecc., E non vale la pena provarlo.

Un nodo per il consiglio di PST ...

"efficienza" :(BACIO passarlo come si passa ogni altro intero sanguinante -.. Pst

... anche se, a volte si applica BACIO a modello parametri e renderli tutti costanti T & anche se alcuni possono essere inseriti nei registri ....

7

Passarli come boost::call_traits<int64_t>::param_type. Questo modello acquisisce le migliori pratiche per il passaggio di qualsiasi tipo sulle piattaforme supportate. su piattaforme a 32 e 64 bit, ma puoi usare lo stesso codice ovunque. Funziona anche io Altri modelli in cui non si conosce ancora il tipo preciso.

+10

+1 questa è di gran lunga la punizione migliore per le persone preoccupate di ottimizzare il passaggio degli interi, che devono digitare quel lotto. –

+0

Forse è vero che per i dati a 64 bit la differenza è trascurabile. Tuttavia, lo spirito della domanda vale la pena imo. Cosa succede se ho una struttura da 12 byte? 16 byte? Il commento di Hans Passant, sebbene possa non essere verificato o testato tecnicamente, dà un'indicazione nella giusta direzione. –

+0

Ovviamente, è utile sapere che per 64 bit non è necessario preoccuparsi :). (Anche se il nostro codice chiamerà questo tipo di funzioni 100s of Million times e durerà per ore in generale.In tal caso, è sempre bene seguire le "migliori" pratiche "). –

1

usare un po 'di buon senso,

  1. se l'oggetto richiede un costruttore di copia complesso, è probabilmente la pena il passaggio per riferimento (dicendo che - un sacco di oggetti di spinta sono progettati per essere passato-by- valore piuttosto che riferimento semplicemente perché l'implementazione interna è piuttosto banale) C'è uno strano che non ho davvero elaborato, std::string, lo passo sempre per riferimento ...

  2. Se si intende modificare il valore che è passato, usa un riferimento

  3. Altrimenti, PASS-BY-VALUE!

Avete un particolare collo di bottiglia delle prestazioni con argomenti alle funzioni? Altrimenti, non spendere troppo tempo a preoccuparsi di che è il modo migliore per passare ...

Ottimizzare da preoccuparsi di come un int è passato in è come pi ** ing nel mare ...

+0

Mi piacerebbe risolvere il puzzle:" magnaccia nel mare " – weberc2

Problemi correlati