Un exemple où un pointeur const est hautement applicable peut être démontré ainsi. Considérez que vous avez une classe avec un tableau dynamique à l'intérieur, et que vous souhaitez transmettre l'accès utilisateur au tableau, mais sans leur accorder les droits de modifier le pointeur. Considérer:
#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());
}
Ce qui produit:
Données d'entrée
mettre des données
Mais si nous essayons ceci:
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
}
On a:
erreur: lvalue requise comme opérande gauche de l'affectation // Drat déjoué à nouveau!
Il est donc clair que nous pouvons modifier le contenu du tableau, mais pas le pointeur du tableau. Bon si vous voulez vous assurer que le pointeur a un état cohérent lors du renvoi à l'utilisateur. Il y a cependant un hic:
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!
}
Nous pouvons toujours supprimer la référence mémoire du pointeur, même si nous ne pouvons pas modifier le pointeur lui-même.
Donc, si vous voulez que la référence mémoire pointe toujours vers quelque chose (IE ne doit jamais être modifié, de la même manière qu'une référence fonctionne actuellement), alors c'est hautement applicable. Si vous voulez que l'utilisateur ait un accès complet et le modifie, alors non-const est pour vous.
Éditer:
Après avoir noté le commentaire okorz001 de ne pas pouvoir attribuer en raison de GetArray () étant un opérande de bonne valeur, son commentaire est tout à fait correct, mais ce qui précède s'applique toujours si vous deviez renvoyer une référence au pointeur (je suppose que j'ai supposé que GetArray était référant une référence), par exemple:
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
}
Reviendra dans le premier entraînant une erreur:
erreur: affectation de l'emplacement en lecture seule 'Temp.TestA :: GetArray ()'
Mais le second se produira joyeusement malgré les conséquences potentielles sur le dessous.
Évidemment, la question se posera «pourquoi voudriez-vous renvoyer une référence à un pointeur»? Il existe de rares cas où vous devez attribuer de la mémoire (ou des données) directement au pointeur d'origine en question (par exemple, créer votre propre front-end malloc / free ou new / free), mais dans ces cas, il s'agit d'une référence non-const . Une référence à un pointeur const Je n'ai pas rencontré de situation qui le justifierait (à moins que peut-être en tant que variables de référence const déclarées plutôt que de types de retour?).
Considérez si nous avons une fonction qui prend un pointeur const (par opposition à un qui ne le fait pas):
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'erreur dans le const produit ainsi le message:
erreur: décrémentation du paramètre en lecture seule 'Data'
Ce qui est bien car nous ne voulons probablement pas faire cela, à moins que nous ne voulions causer les problèmes indiqués dans les commentaires. Si nous éditons le décrément dans la fonction const, ce qui suit se produit:
NonConst: A
Const: B
Clairement, même si A est «Data [1]», il est traité comme «Data [0]» car le pointeur NonConst a permis l'opération de décrémentation. Avec le const implémenté, comme une autre personne l'écrit, nous détectons le bogue potentiel avant qu'il ne se produise.
Une autre considération principale, est qu'un pointeur const peut être utilisé comme une pseudo référence, en ce que la chose vers laquelle la référence pointe ne peut pas être modifiée (on se demande si c'est peut-être ainsi qu'elle a été implémentée). Considérer:
int main()
{
int A = 10;
int * const B = &A;
*B = 20; //This is permitted
printf("%d\n",A);
B = NULL; //This produces an error
}
Lors de la tentative de compilation, génère l'erreur suivante:
erreur: affectation de la variable en lecture seule 'B'
Ce qui est probablement une mauvaise chose si une référence constante à A était souhaitée. Si B = NULL
est commenté, le compilateur se fera un plaisir de nous laisser modifier *B
et donc A. Cela peut ne pas sembler utile avec ints, mais considérez si vous aviez une seule position d'une application graphique où vous vouliez un pointeur non modifiable qui y faisait référence que vous pourriez passer autour.
Son utilisation est variable (excusez le jeu de mots involontaire), mais utilisé correctement, c'est un autre outil dans la boîte pour aider à la programmation.