Un esempio di dove un puntatore const è altamente applicabile può essere dimostrato in questo modo. Considera di avere una classe con un array dinamico al suo interno e desideri passare all'utente l'accesso all'array ma senza concedere loro i diritti per modificare il puntatore. Tener conto di:
#include <new>
#include <string.h>
class TestA
{
private:
char *Array;
public:
TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
~TestA(){if(Array != NULL){ delete [] Array;} }
char * const GetArray(){ return Array; }
};
int main()
{
TestA Temp;
printf("%s\n",Temp.GetArray());
Temp.GetArray()[0] = ' '; //You can still modify the chars in the array, user has access
Temp.GetArray()[1] = ' ';
printf("%s\n",Temp.GetArray());
}
Che produce:
I dati di input
mettono i dati
Ma se proviamo questo:
int main()
{
TestA Temp;
printf("%s\n",Temp.GetArray());
Temp.GetArray()[0] = ' ';
Temp.GetArray()[1] = ' ';
printf("%s\n",Temp.GetArray());
Temp.GetArray() = NULL; //Bwuahahahaa attempt to set it to null
}
Noi abbiamo:
errore: lvalue richiesto come operando di sinistra dell'assegnazione // Drat nuovamente sventato!
Quindi chiaramente possiamo modificare il contenuto dell'array, ma non il puntatore dell'array. Buono se vuoi assicurarti che il puntatore abbia uno stato coerente quando lo restituisci all'utente. C'è un problema, però:
int main()
{
TestA Temp;
printf("%s\n",Temp.GetArray());
Temp.GetArray()[0] = ' ';
Temp.GetArray()[1] = ' ';
printf("%s\n",Temp.GetArray());
delete [] Temp.GetArray(); //Bwuahaha this actually works!
}
Possiamo ancora eliminare il riferimento di memoria del puntatore, anche se non possiamo modificare il puntatore stesso.
Quindi, se si desidera che il riferimento di memoria punti sempre a qualcosa (IE non viene mai modificato, simile a come funziona attualmente un riferimento), allora è altamente applicabile. Se vuoi che l'utente abbia pieno accesso e modificarlo, allora non-const fa per te.
Modificare:
Dopo aver notato il commento di okorz001 di non essere in grado di assegnare a causa del fatto che GetArray () è un operando di valore corretto, il suo commento è del tutto corretto, ma quanto sopra vale ancora se si dovesse restituire un riferimento al puntatore (suppongo di aver presupposto che GetArray fosse riferimento a un riferimento), ad esempio:
class TestA
{
private:
char *Array;
public:
TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
~TestA(){if(Array != NULL){ delete [] Array;} }
char * const &GetArray(){ return Array; } //Note & reference operator
char * &GetNonConstArray(){ return Array; } //Note non-const
};
int main()
{
TestA Temp;
Temp.GetArray() = NULL; //Returns error
Temp.GetNonConstArray() = NULL; //Returns no error
}
Restituirà nel primo con conseguente errore:
errore: assegnazione della posizione di sola lettura 'Temp.TestA :: GetArray ()'
Ma il secondo si verificherà allegramente nonostante le potenziali conseguenze sul lato inferiore.
Ovviamente, verrà sollevata la domanda "perché dovresti voler restituire un riferimento a un puntatore"? Ci sono rari casi in cui è necessario assegnare memoria (o dati) direttamente al puntatore originale in questione (ad esempio, costruendo il proprio front-end malloc / free o new / free), ma in questi casi è un riferimento non const . Un riferimento a un puntatore const Non mi sono imbattuto in una situazione che lo giustifichi (a meno che non sia forse come variabili di riferimento const dichiarate piuttosto che tipi di ritorno?).
Considera se abbiamo una funzione che accetta un puntatore const (rispetto a uno che non lo fa):
class TestA
{
private:
char *Array;
public:
TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
~TestA(){if(Array != NULL){ delete [] Array;} }
char * const &GetArray(){ return Array; }
void ModifyArrayConst(char * const Data)
{
Data[1]; //This is okay, this refers to Data[1]
Data--; //Produces an error. Don't want to Decrement that.
printf("Const: %c\n",Data[1]);
}
void ModifyArrayNonConst(char * Data)
{
Data--; //Argh noo what are you doing?!
Data[1]; //This is actually the same as 'Data[0]' because it's relative to Data's position
printf("NonConst: %c\n",Data[1]);
}
};
int main()
{
TestA Temp;
Temp.ModifyArrayNonConst("ABCD");
Temp.ModifyArrayConst("ABCD");
}
L'errore nel const produce quindi il messaggio:
errore: decremento del parametro di sola lettura 'Dati'
Il che è positivo perché probabilmente non vogliamo farlo, a meno che non vogliamo causare i problemi indicati nei commenti. Se modifichiamo il decremento nella funzione const, si verifica quanto segue:
NonConst: A
Const: B
Chiaramente, anche se A è 'Data [1]', viene trattato come 'Data [0]' perché il puntatore NonConst ha permesso l'operazione di decremento. Con la const implementata, come scrive un'altra persona, rileviamo il potenziale bug prima che si verifichi.
Un'altra considerazione principale è che un puntatore const può essere usato come pseudo riferimento, in quanto la cosa a cui punta il riferimento non può essere cambiata (ci si chiede, se forse è così che è stato implementato). Tener conto di:
int main()
{
int A = 10;
int * const B = &A;
*B = 20; //This is permitted
printf("%d\n",A);
B = NULL; //This produces an error
}
Quando si tenta di compilare, produce il seguente errore:
errore: assegnazione della variabile di sola lettura 'B'
Il che è probabilmente una brutta cosa se si volesse un riferimento costante ad A. Se B = NULL
viene commentato, il compilatore ci lascerà felicemente modificare *B
e quindi A. Questo potrebbe non sembrare utile con ints, ma considera se hai una singola posizione di un'applicazione grafica in cui desideri un puntatore non modificabile che ti fa riferimento che potresti passare in giro.
Il suo utilizzo è variabile (scusate il gioco di parole non intenzionale), ma usato correttamente, è un altro strumento nella scatola per aiutare con la programmazione.