2015-10-05 16 views
9

Attualmente sto imparando C++ da C++ Primer e spiega come un riferimento è un alias per un altro nome di variabile. Spiega anche come un puntatore punta a un'altra variabile. Afferma che la differenza tra un puntatore e un riferimento è che i puntatori possono essere riassegnati e i riferimenti non possono.Qual è la differenza funzionale tra un puntatore const (non un puntatore a const) e un riferimento?

Nell'esempio di codice seguente, cosa posso fare con il puntatore o il riferimento che non riesco a fare con l'altro?

double pi = 3.14; 
double &piRef = pi; 
double *const piPnt = π 

//both of these examples are valid and do the same thing 
piRef = 3.14159; 
*piPnt = 3.14159; 

//however, if I attempt to reassign what the pointer points to, it is illegal. 
//this is the same as with a reference, as a reference can't be reassigned either 
double tau = 6.28; 
piPnt = τ 

sono consapevole delle differenze interne di ciascuno (come un puntatore che è un oggetto, un riferimento non è). Sono interessato a come queste differenze siano importanti per il programmatore oltre una sintassi leggermente diversa. In quanto tale, questo non è un duplicato della domanda this in cui la risposta accettata parla solo di differenze interne.

+0

@juanchopanza Il puntatore nel mio esempio è un puntatore const, pertanto non può essere riassegnato. – john01dav

+0

Ma è possibile utilizzare l'assegnazione sul riferimento. Ricorda solo che è un alias per qualcos'altro. – juanchopanza

+0

@juanchopanza Posso riassegnare il valore a cui punta il puntatore. Ad esempio, sia 'piRef = 3.14159' che' * piPnt = 3.14169' sarebbero validi. Un puntatore può essere const senza puntare a un oggetto const. – john01dav

risposta

5

Da un punto di vista funzionale, puntatori e riferimenti sono effettivamente la stessa cosa ... fanno riferimento a un oggetto e non sono una copia di tale oggetto.

L'unica vera differenza oltre a non essere in grado di riassociare un riferimento è che un puntatore può essere NULL (vale a dire che non punta a nulla) mentre si presume che un riferimento faccia sempre riferimento a un oggetto.

Tecnicamente può effettivamente finiscono con un riferimento che fa riferimento alcun oggetto (ad esempio passando *p ad una funzione che si aspetta un riferimento dove p è il puntatore nullo), ma questo è "comportamento indefinito".

In altre parole puntatori sono più "flessibile" di riferimenti e questo permette al compilatore di ignorare

  • Che un riferimento può modificare l'oggetto è riferimento
  • un riferimento non può avere alcun oggetto

E questo in alcuni casi può produrre codice più veloce.

Il "prezzo" da pagare per l'ulteriore flessibilità di rebinding e di avere NULL s è che la sintassi è (in qualche modo gratuita) più fastidiosa.

+1

In quali casi dovrei voler usare un const nullo puntatore? Se non ha utilità, potrebbe anche non esistere - certamente non è rilevante allora. – john01dav

+0

Le tue due condizioni dicono che il compilatore può ignorare due cose che per quanto ne so non esistono. Un riferimento non può puntare a un non oggetto né può cambiare ciò a cui fa riferimento. – john01dav

+1

@ john01dav: esattamente.Queste cose in C++ sono impossibili (un tempo di compilazione sintattica e forzata, l'altro perché non è supportato e non definito), quindi il compilatore può generare un codice migliore del codice che avrebbe dovuto generare se fosse possibile. Per esempio '++ x' fatto molte volte in una funzione dove' x' è un 'int e' non ha bisogno di ricaricare mai l'indirizzo del numero intero referenziato, mentre con '(* p) ++' dove 'p' è un puntatore che il compilatore deve anche considerare che 'p' potrebbe essere cambiato (anche probabilmente a causa dell'aliasing). – 6502

1

Cosa posso fare con il puntatore o riferimento che non posso fare con l' altro?

double *const piPnt = π 

La dichiarazione di cui sopra

marks piPnt as a read only variable in memory layout 

Quindi, piPnt = &xyz avrebbe generato un errore ora.

Tuttavia, la modifica del valore all'indirizzo indicato dal puntatore è ancora valida.

Cioè, *piPnt = 56 va bene.

I puntatori di Const sono utili nei sistemi incorporati che devono fare riferimento alla stessa memoria (mappatura delle porte). È una mappatura unica e puntatori costanti sono utili qui.

Ora per quanto riguarda i riferimenti:

double &piRef = pi; 

Non si può reinizializzare un punto di riferimento in C++. È possibile assegnare un valore diverso all'oggetto a cui si riferisce. Questo è lo stesso oggetto per quel riferimento per sempre. E questo è quello che hai fatto nel tuo esempio.

piRef = 3.14159; 

Un riferimento non può essere modificato per fare riferimento a un altro oggetto dopo inizializzazione. Si noti che l'inizializzazione di un riferimento viene trattata allo in modo molto diverso dall'assegnazione ad esso. Il passaggio di argomenti (5.2.2) e il valore della funzione (6.6.3) sono inizializzazioni.

Alcuni luoghi in cui i riferimenti sono utili:

  1. puntatori non può puntare al provvisori, lo standard espressamente vieta di farlo. Le referenze possono legarsi ai provvisori.
  2. Un puntatore può essere NULL mentre si presume che un riferimento faccia sempre riferimento a un oggetto. Puoi ancora restituire null da una funzione che restituisce un riferimento, il compilatore non si lamenterebbe, ma è un suicidio.
+0

Sembra che tu stia citando le somiglianze tra un puntatore const e un riferimento e le differenze tra un puntatore non-const e un riferimento. Sto cercando le differenze tra un puntatore const e un riferimento. – john01dav

+0

di conseguenza, modificato ora. – basav

4

cosa posso fare con il puntatore o riferimento che non posso fare con l'altro?

riferimenti consentono di scrivere alcuni costruttori e operatori di sovraccarico:

class X 
{ 
    // copy constructor 
    X(const X& a); 

    // move constructor 
    X(X&& a); 

    // copy assignment operator 
    X& operator=(const X& a); 

    // move assignment operator 
    X& operator=(X&& a); 
} 

(. In effetti, l'overloading degli operatori è stato il caso motivante uso per l'introduzione di riferimenti in C++)

cosa viene spesso trascurato è il fatto che il C++ moderno distingua tra X& (un riferimento a un lvalue) e X&& (un riferimento a un valore di rvalore), ma non esiste un puntatore a un valore di rvalore.

Problemi correlati