Prerequisito: Puntatori , Riferimenti
C e C++ supportano i puntatori, il che è diverso dalla maggior parte degli altri linguaggi di programmazione come Java, Python, Ruby, Perl e PHP poiché supportano solo i riferimenti. Ma è interessante notare che il C++, insieme ai puntatori, supporta anche i riferimenti.
logo Java
In superficie, sia i riferimenti che i puntatori sono molto simili poiché entrambi vengono utilizzati per fare in modo che una variabile fornisca accesso a un'altra. Poiché entrambi forniscono molte delle stesse funzionalità, spesso non è chiaro cosa ci sia di diverso tra questi meccanismi. In questo articolo cercherò di illustrare le differenze tra puntatori e riferimenti.
Puntatori : Un puntatore è una variabile che contiene l'indirizzo di memoria di un'altra variabile. È necessario dereferenziare un puntatore con il comando * all'operatore di accedere alla posizione di memoria a cui punta.
Riferimenti : Una variabile di riferimento è un alias, ovvero un altro nome per una variabile già esistente. Un riferimento, come un puntatore, viene implementato anche memorizzando l'indirizzo di un oggetto.
Un riferimento può essere pensato come un puntatore costante (da non confondere con un puntatore a un valore costante!) con indiretto automatico, ovvero il compilatore applicherà il * operatore per te.
int i = 3; // A pointer to variable i or 'stores the address of i' int *ptr = &i; // A reference (or alias) for i. int &ref = i;>
Differenze :
1. Inizializzazione: Un puntatore può essere inizializzato in questo modo:
int a = 10; int *p = &a; // OR int *p; p = &a;>
Possiamo dichiarare e inizializzare il puntatore nello stesso passaggio o su più righe.
2. Nei riferimenti,
int a = 10; int &p = a; // It is correct // but int &p; p = a; // It is incorrect as we should declare and initialize references at single step>
NOTA: Questa differenza può variare da compilatore a compilatore. La differenza di cui sopra riguarda Turbo IDE.
3. Riassegnazione: Un puntatore può essere riassegnato. Questa proprietà è utile per l'implementazione di strutture dati come una lista concatenata, un albero, ecc. Vedi l'esempio seguente:
int a = 5; int b = 6; int *p; p = &a; p = &b;>
4. D'altra parte, un riferimento non può essere riassegnato e deve essere assegnato al momento dell'inizializzazione.
int a = 5; int b = 6; int &p = a; int &p = b; // This will throw an error of 'multiple declaration is not allowed' // However it is valid statement, int &q = p;>
5. Indirizzo di memoria: Un puntatore ha il proprio indirizzo di memoria e dimensione nello stack, mentre un riferimento condivide lo stesso indirizzo di memoria con la variabile originale e non occupa spazio nello stack.
int &p = a; cout << &p << endl << &a;>
6. Valore NULL: A un puntatore può essere assegnato direttamente NULL, mentre un riferimento non può esserlo. I vincoli associati ai riferimenti (nessun NULL, nessuna riassegnazione) assicurano che le operazioni sottostanti non si imbattano in una situazione di eccezione.
7. Indiretto: È possibile avere un puntatore a puntatore (noto come doppio puntatore) che offre livelli aggiuntivi di indiretto, mentre i riferimenti offrono solo un livello di indiretto. Per esempio,
In Pointers, int a = 10; int *p; int **q; // It is valid. p = &a; q = &p; // Whereas in references, int &p = a; int &&q = p; // It is reference to reference, so it is an error>
8. Operazioni aritmetiche: Varie operazioni aritmetiche possono essere eseguite sui puntatori, mentre non esiste una cosa chiamata Aritmetica dei riferimenti (tuttavia, puoi eseguire l'aritmetica dei puntatori sull'indirizzo di un oggetto puntato da un riferimento, come in &obj + 5).
Forma tabulare della differenza tra riferimenti e puntatori in C++
| Riferimenti | Puntatori | |
|---|---|---|
| Riassegnazione | La variabile non può essere riassegnata in Riferimento. | La variabile può essere riassegnata in Puntatori. |
| Indirizzo di memoria | Condivide lo stesso indirizzo della variabile originale. | I puntatori hanno il proprio indirizzo di memoria. |
| Lavoro | Si riferisce ad un'altra variabile. | Sta memorizzando l'indirizzo della variabile. |
| Valore nullo | Non ha valore nullo. | Può avere un valore assegnato come null. |
| argomenti | A questa variabile fa riferimento il metodo pass by value. | Il puntatore funziona con il metodo noto come passaggio per riferimento. |
Quando usare Cosa
Le prestazioni sono esattamente le stesse in quanto i riferimenti sono implementati internamente come puntatori. Tuttavia, puoi tenere a mente alcuni punti per decidere quando utilizzare cosa:
- Usa riferimenti:
- Nei parametri della funzione e nei tipi restituiti.
- Usa i puntatori:
- Se è necessaria l'aritmetica del puntatore o il passaggio di un puntatore NULL. Ad esempio, per gli array (nota che l'accesso a un array viene implementato utilizzando l'aritmetica dei puntatori).
- Implementare strutture di dati come una lista concatenata, un albero, ecc. e i relativi algoritmi. Questo perché, per puntare a celle diverse, dobbiamo usare il concetto di puntatori.
Citato nelle domande frequenti su C++ Lite : usa i riferimenti quando puoi e i puntatori quando devi. I riferimenti sono generalmente preferiti ai puntatori ogni volta che non è necessario riposizionarli. Questo di solito significa che i riferimenti sono più utili nell’interfaccia pubblica di una classe. I riferimenti in genere appaiono sulla pelle di un oggetto e i puntatori all'interno.
L'eccezione a quanto sopra è quando il parametro di una funzione o il valore restituito necessitano di un riferimento sentinella, un riferimento che non si riferisce a un oggetto. Di solito è meglio farlo restituendo/prendendo un puntatore e dando al valore nullptr questo significato speciale (i riferimenti devono sempre essere alias di oggetti, non un puntatore null dereferenziato).
Articolo correlato:
Quando passiamo gli argomenti come riferimento o puntatori?