Puntatori e Costanti

 


 

Puntatori a costante

 

Nelle definizioni di una variabile puntatore, lo specificatore di tipo const indica che deve essere considerata costante la variabile puntata (non il puntatore!).

Es.:           const  float* ptr;
definisce il puntatore variabile ptr a costante float.

In realtà a un puntatore a costante si può anche assegnare l'indirizzo di una variabile, ma non é vero il contrario: l'indirizzo di una costante può essere assegnato solo a un puntatore a costante. In altre parole il C++ accetta conversioni da puntatore a variabile a puntatore a costante, ma non viceversa.

L'operazione di deref. di un puntatore a costante non é mai accettata come l-value, anche se la variabile puntata non é const.

Es.: int datov=50; (datov é una variabile int)
const int datoc=50; (datoc é una costante int)
int* ptv; (ptv é un puntatore a variabile int)
const int* ptc; (ptc é un puntatore a costante int)
ptc = &datov; (valida, in quanto le conversioni da int* a const int* sono ammesse)
ptv = &datoc; (non valida, in quanto le conversioni da const int* a int* non sono ammesse)
*ptc = 10; (deref. l-value non valida, anche se ptc punta a una variabile)
datov=10;  cout << *ptc;    (deref. r-value valida, scrive 10)

 


 

Puntatori costanti

 

I puntatori costanti si definiscono specificando l'operatore di dichiarazione * const (al posto di *)

Es.:           float* const  ptr;
definisce il puntatore costante ptr a variabile float

Un puntatore costante segue la regola di tutte le costanti: deve essere inizializzato, ma non può più essere modificato (non é un l-value). Resta l-value, invece, la deref. di un puntatore costante che punta a una variabile.

Es.: int dato1,dato2; (dato1 e dato2 sono due variabili int)
int* const ptr = &dato1; (ptr é un puntatore costante, inizializzato con l'indirizzo di dato1)
*ptr = 10; (valida, in quanto ptr punta a una variabile)
ptr = &dato2; (non valida, in quanto ptr é costante)

 
Casi tipici di puntatori costanti sono gli array.

 


 

Puntatori costanti a costante

 

Ripetendo due volte const (come specificatore di tipo e come operatore di dichiarazione), si può definire un puntatore costante a costante (di uso piuttosto raro).

Es.: const char dato='A'; (dato é una costante char, inizializzata con 'A')
const char* const ptr = &dato; (ptr é un puntatore costante a costante , inizializzato con l'indirizzo della costante dato)

   
Nel caso di un puntatore costante a costante, non sono l-values né il puntatore né la sua deref.

 


 

Funzioni con argomenti costanti trasmessi by value

 

Le regole di ammissibilità degli argomenti di una funzione, dichiarati const (nella funzione e/o nel programma chiamante) e trasmessi by value, sono riconducibili alle regole generali applicate a una normale dichiarazione con inizializzazione; come é noto, infatti, la trasmissione by value comporta una creazione per copia, che equivale alla dichiarazione dell'argomento come variabile locale della funzione, inizializzata con il valore passato dal programma chiamante.

Quindi un argomento può essere dichiarato const nel programma chiamante e non nella funzione o viceversa, senza limitazioni (in quanto la creazione per copia "separa i destini" delle due variabili), salvo in un caso: un puntatore a costante non può essere dichiarato tale nel programma chiamante se non lo é anche nella funzione (in quanto non sono ammesse le conversioni da puntatore a costante a puntatore a variabile).

Es.: void funz(int*);    void main() { const int* ptr; ... funz(ptr); ... }
(errore : l'argomento é dichiarato puntatore a costante nel main e puntatore a variabile nella funzione)
void funz(const int*);      void main() {int*ptr; ... funz(ptr); ... }
( ok! )

   
Da quest'ultimo esempio si capisce anche qual'é l'uso principale di un puntatore a costante: come argomento passato a una funzione, se non si desidera che la variabile puntata subisca modifiche dall'interno della funzione stessa (tramite operazioni di deref.), anche se ciò é possibile nel programma chiamante.

 


 

Funzioni con argomenti costanti trasmessi by reference

 

Sappiamo che, se un argomento é passato a una funzione by reference, non ne viene costruita una copia, ma il suo nome nella funzione é assunto come alias del nome corrispondente nel programma chiamante (cioè i due nomi si riferiscono alla stessa locazione di memoria). Per questo motivo il controllo sui tipi e più rigoroso rispetto al caso di passaggio by value: in particolare, qualsiasi sia l'argomento (puntatore o no), non é ammesso dichiararlo const nel programma chiamante e non nella funzione.

La dichiarazione inversa (const solo nella funzione) é invece possibile, in quanto corrisponde alla definizione di un alias di sola lettura: l'argomento, pur essendo modificabile nel programma chiamante, non lo é dall'interno della funzione.

Il passaggio by reference di argomenti dichiarati const nella funzione é in uso molto frequente in C++, perché combina insieme due vantaggi: quello di proteggere i dati del programma da modifiche indesiderate (come nel passaggio by value), e quello di una migliore efficienza; infatti il passaggio by reference, non comportando la creazione di nuove variabili, é più veloce del passaggio by value.

Quando un argomento é passato by reference ed é dichiarato const nella funzione, non esiste più la condizione che nel programma chiamante il corrispondente argomento sia un l-value (può anche essere il risultato di un'espressione).

Se si vuole dichiarare un argomento: puntatore costante passato by reference, bisogna specificare entrambi gli operatori di dichiarazione *const e & (nell'ordine)
Es.: funz(int* const & ptr);
dichiara che l'argomento ptr é un puntatore costante a variabile int, passato by reference

 


 

Torna all'Indice