Suppression d'un pointeur vers const (T const *)

89

J'ai une question de base concernant les pointeurs const. Je ne suis pas autorisé à appeler des fonctions membres non const à l'aide d'un pointeur const. Cependant, je suis autorisé à le faire sur un pointeur const:

delete p;

Cela appellera le destructeur de la classe qui est essentiellement une «méthode» non-const. Pourquoi est-ce permis? Est-ce juste pour soutenir ceci:

delete this;

Ou y a-t-il une autre raison?

Naveen
la source

Réponses:

112

C'est pour soutenir:

// dynamically create object that cannot be changed
const Foo * f = new Foo;

// use const member functions here

// delete it
delete f;

Mais notez que le problème ne se limite pas aux objets créés dynamiquement:

{
 const Foo f;
 // use it
} // destructor called here

Si les destructeurs ne pouvaient pas être appelés sur les objets const, nous ne pourrions pas du tout utiliser d'objets const.

Agnel Kurian
la source
21
+1 pour la dernière modification. Je pense que c'est la vraie raison. Appel de destructeur automatique pour l'objet const - presque identique à delete f; où f - pointeur sur const.
bayda
const Foo * fou Foo const * fn'est pas un pointeur const vers Foo. C'est un pointeur vers const Foo. Foo * const f est un pointeur const vers Foo.
user11373693
48

En d'autres termes, si ce n'était pas autorisé, il n'y aurait aucun moyen de supprimer des objets const sans utiliser const_cast.

Sémantiquement, const est une indication qu'un objet doit être immuable. Cela n'implique cependant pas que l'objet ne doit pas être supprimé.

PaulJWilliams
la source
3
Les destructeurs peuvent faire muter des objets de manière assez violente, donc cela doit être une étrange utilisation du mot `` immuable '' dont je n'étais pas au courant auparavant ...
DarthGizka
1
@DarthGizka non, les destructeurs vous emmènent d'un état où il y a un objet à un autre où il n'y en a pas. C ++ ne définit aucune méthode pour observer une «mutation» post destruction
Caleth
@ Caleth: la norme peut ne pas vous permettre de regarder l'objet une fois son destructeur terminé, mais vous êtes certainement autorisé à regarder les effets secondaires causés par la destruction. Par conséquent, les circonstances peuvent facilement être arrangées pour rendre observable la mutation de l'objet «immuable». Aux États-Unis, le meurtre est difficile à poursuivre lorsqu'il n'y a pas de corps, mais il s'agit toujours d'un meurtre (et il peut y avoir d'autres preuves suffisantes pour une condamnation). Même différence.
DarthGizka
6

Je ne suis pas autorisé à appeler des fonctions membres non const à l'aide d'un pointeur const.

Oui, vous l'êtes.

class Foo
{
public:
  void aNonConstMemberFunction();
};

Foo* const aConstPointer = new Foo;
aConstPointer->aNonConstMemberFunction(); // legal

const Foo* aPointerToConst = new Foo;
aPointerToConst->aNonConstMemberFunction(); // illegal

Vous avez confondu un pointeur const vers un objet non const, avec un pointeur non const vers un objet const.

Ayant dit cela,

delete aConstPointer; // legal
delete aPointerToConst; // legal

il est légal de supprimer non plus, pour les raisons déjà indiquées par les autres réponses ici.

Oktaliste
la source
5

Les constructeurs et les destructeurs ne doivent pas être considérés comme des «méthodes». Ce sont des constructions spéciales pour initialiser et détruire un objet d'une classe.

«const pointer» indique que l'état de l'objet ne sera pas modifié lorsque des opérations sont effectuées sur celui-ci alors qu'il est en vie.

Indy9000
la source
5

Une autre façon de voir les choses: la signification précise d'un pointeur const est que vous ne pourrez pas modifier l'objet pointé qui serait visible via ce pointeur ou tout autre pointeur ou référence au même objet. Mais lorsqu'un objet est détruit, tous les autres pointeurs vers l'adresse précédemment occupée par l'objet maintenant supprimé ne sont plus des pointeurs vers cet objet . Ils stockent la même adresse, mais cette adresse n'est plus l'adresse d'aucun objet (en fait elle pourra bientôt être réutilisée comme adresse d'un objet différent).

Cette distinction serait plus évidente si les pointeurs en C ++ se comportaient comme des références faibles, c'est-à-dire que dès que l'objet est détruit, tous les pointeurs existants vers lui seraient immédiatement positionnés sur 0. (C'est le genre de chose considérée comme trop coûteuse à l'exécution pour l'imposer à tous les programmes C ++, et en fait, il est impossible de la rendre entièrement fiable.)

MISE À JOUR : En lisant cela neuf ans plus tard, c'est avocat-ish. Je trouve maintenant votre réaction initiale compréhensible. Interdire la mutation mais permettre la destruction est clairement problématique. Le contrat implicite des pointeurs / références const est que leur existence agira comme un blocage lors de la destruction de l'objet cible, c'est-à-dire le garbage collection automatique.

La solution habituelle à cela est d'utiliser presque n'importe quelle autre langue à la place.

Daniel Earwicker
la source
Si vous ne pouvez pas détruire les choses pointées par des pointeurs vers const, comment gérez-vous la std::unique_ptr<const T>fin de sa vie?
Caleth le
@Caleth alors il n'y aurait pas de solution à cela en C ++. Ce n'est qu'un exemple du problème général: en C ++, le modificateur const signifie «Vous ne pouvez pas muter la cible, sauf dans un sens où vous pouvez complètement la détruire et rendre toutes les autres références à elle invalides et sources de comportement indéfini». C'est pourquoi je pense que ce genre de question devrait être une incitation à envisager d'autres langues. Il contient des trous UB qui ne peuvent être résolus sans adopter une approche de base différente.
Daniel Earwicker du