2010-04-06 11 views
29

Da quello che ho capito: quando passi di valore, la funzione crea una copia locale dell'argomento passato e la usa; quando la funzione termina, diventa fuori portata. Quando si passa da riferimento const, la funzione utilizza un riferimento all'argomento passato che non può essere modificato. Non capisco, tuttavia, perché uno dovrebbe scegliere uno sull'altro, tranne in una situazione in cui un argomento deve essere modificato e restituito. Se avessi una funzione di vuoto in cui non viene restituito nulla, perché sceglierne uno rispetto all'altro?Perché passare per riferimento const anziché per valore?

MODIFICA: Quindi passando di riferimento const evita di copiare l'oggetto. Quindi in quali situazioni si copia bene l'oggetto? Voglio dire, perché non usare sempre i riferimenti const sempre se ottimizza continuamente le prestazioni?

+1

possibile duplicato di http://stackoverflow.com/questions/1567138/const-t-arg-vs-t-arg –

+0

L'articolo gf links copre la tua seconda domanda. In breve: se avete bisogno di una copia, passatene una. –

+0

@ Kirill Ah, questo risponde alla mia domanda. Ho cercato "pass by const reference" e non ha attivato nulla, quindi ho perso quello. – Maulrus

risposta

39

Ci sono due considerazioni principali. Uno è la spesa per copiare l'oggetto passato e il secondo è l'ipotesi che il compilatore può fare quando l'oggetto è un oggetto locale.

E.g. Nel primo modulo, nel corpo di f non si può presumere che a e non facciano riferimento allo stesso oggetto; quindi il valore di a deve essere riletto dopo ogni scrittura su b, per ogni evenienza. Nel secondo modulo, a non può essere modificato tramite una scrittura su b, poiché è locale per la funzione, quindi queste rilette non sono necessarie.

void f(const Obj& a, Obj& b) 
{ 
    // a and b could reference the same object 
} 

void f(Obj a, Obj& b) 
{ 
    // a is local, b cannot be a reference to a 
} 

E.g.: Nel primo esempio, il compilatore può essere in grado di assumere che il valore di un oggetto locale non cambia quando viene effettuata una chiamata non correlata. Senza informazioni su h, il compilatore potrebbe non sapere se un oggetto a cui quella funzione ha un riferimento (tramite un parametro di riferimento) non viene modificato da h. Ad esempio, quell'oggetto potrebbe essere parte di uno stato globale che viene modificato da h.

void g(const Obj& a) 
{ 
    // ... 
    h(); // the value of a might change 
    // ... 
} 

void g(Obj a) 
{ 
    // ... 
    h(); // the value of a is unlikely to change 
    // ... 
} 

Sfortunatamente, questo esempio non è in ghisa. È possibile scrivere una classe che, ad esempio, aggiunge un puntatore a se stesso a un oggetto di stato globale nel suo costruttore, in modo che anche un oggetto locale di tipo classe possa essere modificato da una chiamata di funzione globale. Nonostante ciò, ci sono ancora potenzialmente maggiori opportunità di ottimizzazioni valide per gli oggetti locali in quanto non possono essere alias direttamente direttamente dai riferimenti passati o da altri oggetti preesistenti.

Il passaggio di un parametro tramite const deve essere scelto dove la semantica dei riferimenti è effettivamente richiesta o come miglioramento delle prestazioni solo se il costo del potenziale aliasing viene superato dalla spesa per la copia del parametro.

+0

A volte, la copia dei parametri può anche darti vantaggi per la località. –

+1

Qual è il punto di 'const Obj & a' se i dati di riferimento potrebbero cambiare? Perché persino avere il 'const' in primo luogo? –

4

Effettuare una copia di un oggetto potrebbe influire notevolmente sulle prestazioni in alcuni casi. Si consideri una funzione con argomento std::vector<long> e si desidera passare il vettore con 1 milione di elementi. In questo caso, ti consigliamo di utilizzare il riferimento const passando per valore. In this SO question potresti trovare una semplice regola generale per la tua domanda.

2

A volte, fare una copia di un oggetto può essere costoso e quindi il riferimento pass-by-const eviterà di dover fare quella copia. Altrimenti, direi che dovresti semplicemente passare per valore se è ciò che è semanticamente richiesto.

2

A evitare di effettuare una copia non necessaria, migliorando così le prestazioni.

2

Passare un argomento per valore ha il sovraccarico di una copia dell'oggetto che viene passato alla funzione.

Forse un oggetto non è copiabile e le tue scelte sono limitate.

2

A causa dei vantaggi prestazionali che otterrete. Diciamo che hai un oggetto grande (in termini di dimensioni in byte). Ora, se si passa questo oggetto per valore a una funzione, è necessario creare una copia non necessaria di questo, tuttavia è possibile ottenere lo stesso effetto passando un riferimento const a quell'oggetto stesso senza creare copia. Poiché un riferimento viene normalmente memorizzato come puntatore sotto i cappucci, il costo di passaggio di un riferimento è solo sizeof(pointer).

18

Passare gli argomenti in base al valore e quindi copiarli può essere costoso: i riferimenti const evitano quel passaggio costoso pur promettendo al chiamante che l'oggetto non verrà modificato.

I tipi solitamente fondamentali (int, double, ...) vengono passati per valore, mentre i tipi di classe vengono passati per riferimento const.

Tuttavia, è possibile specificare exceptions dove il valore pass-by per i tipi di classe può essere vantaggioso.

2

Un array non può essere passato per valore, quindi è un buon momento per usare un puntatore const.

Problemi correlati