pointeur typedef const étrangeté

veuillez considérer le code suivant:

typedef struct Person* PersonRef; struct Person { int age; }; const PersonRef person = NULL; void changePerson(PersonRef newPerson) { person = newPerson; } 

Pour une raison quelconque, le compilateur se plaint de la valeur en lecture seule non assignable. Mais le mot-clé const ne doit pas rendre le pointeur const. Des idées?

Notez que

 typedef int* intptr; const intptr x; 

n’est pas la même chose que:

 const int* x; 

intptr est un pointeur sur int. const intptr est un pointeur constant sur int , pas un pointeur sur constant int .

donc, après un pointeur typedef, je ne peux plus le rendre au contenu?

Il y a des manières laides, telles que la macro typeof de gcc:

 typedef int* intptr; intptr dummy; const typeof(*dummy) *x; 

mais, comme vous le voyez, il est inutile de connaître le type derrière intptr .

 const PersonRef person = NULL; 

est

 struct Person*const person= NULL; 

de sorte que vous constituez le pointeur et non l’object.

Alors que le problème est déjà résolu par les réponses ci-dessus, je ne vois pas pourquoi …

Alors peut-être en règle générale:

  1. Le const fait toujours référence à son jeton prédécesseur.
  2. Dans le cas contraire, c’est “consting”, c’est le jeton successeur.

Cette règle peut vraiment vous aider à déclarer un pointeur sur des pointeurs const ou quelque chose d’aussi net.

Quoi qu’il en soit, gardant cela à l’esprit, il faut bien comprendre pourquoi

 struct Person *const person = NULL; 

déclare un pointeur const à une structure mutable.

Pensez-y, votre typedef “groupe” la struct Person avec le jeton de pointeur * . Donc, pour écrire

 const PersonRef person = NULL; 

votre compilateur voit quelque chose comme ceci (pseudo-code):

 const [struct Person *]person = NULL; 

Comme il ne rest plus rien de const , il décompose le jeton dans sa struct Person * droite struct Person * constant.

Eh bien, je pense que c’est la raison pour laquelle je n’aime pas cacher les pointeurs à l’aide des fonts de caractères, alors que j’aime les fonts de caractères en tant que telles. Qu’en est-il de l’écriture

 typedef struct Person { ... } Person; const Person *person; /*< const person */ Person *const pointer; /*< const pointer to mutable person */ 

et il devrait être assez clair pour les compilateurs et les humains, ce que vous faites.

Ne cachez jamais les pointeurs derrière les types de caractères, c’est vraiment une très mauvaise pratique qui ne créera que des bugs.

Un de ces fameux bugs est qu’un type de pointeur typedef: ed déclaré comme const sera traité comme un “pointeur constant sur des données non constantes”, plutôt que “un pointeur non constant sur des données constantes”, ce à quoi on s’attend intuitivement. . C’est ce qui se passe dans votre programme.


Solution:

 typedef struct { int age; } Person; const Person* person = NULL; // non-constant pointer to constant Person 

vous obtenez et erreur

 error: assignment of read-only variable 'person' 

sur déclaration

 person = newPerson; 

parce que vous avez déclaré person en tant que const, sa valeur est uniquement en lecture seule …. la valeur const ne peut pas être modifiée

si vous voulez changer cette TVA alors pourquoi vous la tenez?

supprimer le mot clé const votre code fonctionnera très bien

En complément de la réponse (acceptée) de Piotr, il est possible d’éviter le typeof spécifique à typeof :

 static_assert(std::is_same> *>::value, "not same via type_traits"); static_assert(std::is_same*>::value, "not same via decltype"); 

En changeant foo_t en foo::type ci-dessus et / ou en utilisant la version de boost, il est même possible de faire cela en C ++ 98, bien que ce ne soit joli que depuis C ++ 11.


Vous pouvez également utiliser deux types de fichiers différents, ce qui fonctionne également pour les cas autres que les pointeurs simples. Par exemple, considérons les const_iterator chaque iterator et const_iterator chaque conteneur.