Capisco come con qualsiasi altra variabile, il tipo di parametro determina l’interazione tra il parametro e il suo argomento. La mia domanda è: qual è il motivo dietro il quale si dovrebbe fare riferimento a un parametro e perché non lo si dovrebbe fare? Perché alcuni parametri delle funzioni fanno riferimento e altri no? Hai difficoltà a capire i vantaggi di farlo, qualcuno potrebbe spiegare?
La capacità di passare per riferimento esiste per due motivi:
Esempio per modificare l’argomento
void get5and6(int *f, int *s) // using pointers { *f = 5; *s = 6; }
questo può essere usato come:
int f = 0, s = 0; get5and6(&f,&s); // f & s will now be 5 & 6
O
void get5and6(int &f, int &s) // using references { f = 5; s = 6; }
questo può essere usato come:
int f = 0, s = 0; get5and6(f,s); // f & s will now be 5 & 6
Quando passiamo per riferimento, passiamo l’indirizzo della variabile. Il passaggio per riferimento è simile al passaggio di un puntatore: in entrambi i casi viene trasmesso solo l’indirizzo.
Ad esempio:
void SaveGame(GameState& gameState) { gameState.update(); gameState.saveToFile("save.sav"); } GameState gs; SaveGame(gs)
O
void SaveGame(GameState* gameState) { gameState->update(); gameState->saveToFile("save.sav"); } GameState gs; SaveGame(&gs);
Poiché viene passato solo l’indirizzo, non è necessario copiare il valore della variabile (che potrebbe essere davvero enorme per oggetti enormi). Quindi il passaggio per riferimento migliora le prestazioni soprattutto quando:
Inoltre, leggi i riferimenti const
. Quando viene utilizzato, l’argomento non può essere modificato nella funzione.
Questo articolo mi ha aiutato molto.
Si prega di dimenticare i puntatori per ora. E prendi questo con un granello di sale.
Un riferimento è l’object. Quando passi per riferimento, passi l’ object.
Quando passi per valore, passi una copia dell’object; un altro object. Potrebbe avere lo stesso stato , ma è un’istanza diversa ; un clone
Quindi, può essere sensato passare per riferimento se:
const
. E può avere senso passare di valore se:
int
di riferimento a meno che non volessi modificarlo). Ecco, dai un’occhiata a questo codice:
#include struct Foo { Foo() { } void describe() const { std::cout<<"Foo at address "<
E compilarlo in questo modo: g++ example.cpp
./a.out
: ./a.out
E controlla l'output (gli indirizzi reali potrebbero essere diversi nel tuo computer, ma il punto rimarrà):
Original Foo Foo at address 0x7fff65f77a0f called byreference Foo at address 0x7fff65f77a0f called byvalue Foo at address 0x7fff65f779f0
Si noti come l'indirizzo called byreference
sia lo stesso Original Foo
(entrambi sono 0x7fff65f77a0f
). E nota come l'indirizzo called byvalue
è diverso (è 0x7fff65f779f0
).
Portalo su una tacca. Modifica il codice per apparire come segue:
#include #include // for sleeping struct Foo { Foo() { } Foo(const Foo&) { sleep(10); // assume that building from a copy takes TEN seconds! } void describe() const { std::cout<<"Foo at address "<
Compilalo allo stesso modo e nota l'output (commenti non nell'output, inclusi per chiarezza):
Original Foo Foo at address 0x7fff64d64a0e called byreference Foo at address 0x7fff64d64a0e # this point is reached "immediately" called byvalue # this point is reached TEN SECONDS later Foo at address 0x7fff64d64a0f
Quindi, il codice ha lo scopo di esagerare il costo di una copia: quando hai chiamato per riferimento, questo costo NON è stato sostenuto. Quando hai chiamato per valore, hai dovuto aspettare dieci secondi.
Nota: il mio codice è stato compilato in OS X 10.7.4 utilizzando GCC 4.8.1. Se sei in Windows potresti aver bisogno di qualcosa di diverso da unitsd.h
per far funzionare la chiamata a sleep
.
Forse questo aiuta.
Vantaggi dell’utilizzo di pass per riferimento: non è necessario creare una copia dei dati che si stanno passando solo il puntatore ad essa in memoria. (una grande vittoria per le prestazioni pensa se hai un object enorme che hai passato in giro). È ansible “restituire” più valori. So che alcune funzioni in c / c ++ restituiscono un numero e uno dei parametri è un puntatore ai dati che vengono manipolati.
Contro l’utilizzo del pass per riferimento: bisogna stare attenti a modificare i dati trasmessi in quanto potrebbero causare effetti collaterali che potreste desiderare o meno.
Per riferimento è ugualmente ansible passare manualmente la variabile tramite puntatore, ma per riferimento non consentirà all’utente di gestire il puntatore “facile da rovinare”.