Löschen eines Zeigers auf const (T const *)

87

Ich habe eine grundlegende Frage zu den const-Zeigern. Ich darf keine Nicht-Const-Member-Funktionen mit einem Const-Zeiger aufrufen. Ich darf dies jedoch mit einem const-Zeiger tun:

delete p;

Dies ruft den Destruktor der Klasse auf, der im Wesentlichen eine nicht konstante 'Methode' ist. Warum ist das erlaubt? Ist es nur um dies zu unterstützen:

delete this;

Oder gibt es einen anderen Grund?

Naveen
quelle

Antworten:

110

Es ist zu unterstützen:

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

// use const member functions here

// delete it
delete f;

Beachten Sie jedoch, dass das Problem nicht auf dynamisch erstellte Objekte beschränkt ist:

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

Wenn Destruktoren für const-Objekte nicht aufgerufen werden könnten, könnten wir überhaupt keine const-Objekte verwenden.

Agnel Kurian
quelle
21
+1 für die letzte Bearbeitung. Ich denke, das ist der wahre Grund. Automatischer Destruktoraufruf für const-Objekt - fast identisch mit delete f; wobei f - Zeiger auf const.
Bayda
const Foo * foder Foo const * fist kein konstanter Zeiger auf Foo. Es ist ein Zeiger auf const Foo. Foo * const f ist ein konstanter Zeiger auf Foo.
user11373693
47

Sagen wir es so - wenn es nicht erlaubt wäre, gäbe es keine Möglichkeit, const-Objekte zu löschen, ohne const_cast zu verwenden.

Semantisch ist const ein Hinweis darauf, dass ein Objekt unveränderlich sein sollte. Dies bedeutet jedoch nicht, dass das Objekt nicht gelöscht werden sollte.

PaulJWilliams
quelle
3
Zerstörer können Objekte auf ziemlich gewalttätige Weise mutieren, daher muss dies eine seltsame Verwendung des Wortes "unveränderlich" sein, die mir vorher nicht bekannt war ...
DarthGizka
1
@DarthGizka nein, Destruktoren bringen dich von einem Zustand, in dem es ein Objekt gibt, zu einem Zustand, in dem es kein Objekt gibt. C ++ definiert keine Methode, um eine "Mutation" nach der Zerstörung zu beobachten
Caleth
@ Caleth: Der Standard erlaubt Ihnen möglicherweise nicht, das Objekt zu betrachten, nachdem sein Destruktor vollständig ausgeführt wurde, aber Sie dürfen sicherlich die durch die Zerstörung verursachten Nebenwirkungen betrachten. Daher können Umstände leicht arrangiert werden, um die Mutation des "unveränderlichen" Objekts beobachtbar zu machen. In den USA ist Mord schwer zu verfolgen, wenn es keine Leiche gibt, aber es ist immer noch Mord (und es gibt möglicherweise andere Beweise, die für eine Verurteilung ausreichen). Gleicher Unterschied.
DarthGizka
5

Konstruktoren und Destruktoren sollten nicht als 'Methoden' angesehen werden. Sie sind spezielle Konstrukte zum Initialisieren und Abreißen eines Objekts einer Klasse.

'const pointer' gibt an, dass der Status des Objekts nicht geändert wird, wenn Operationen an ihm ausgeführt werden, während es lebt.

Indy9000
quelle
5

Ich darf keine Nicht-Const-Member-Funktionen mit einem Const-Zeiger aufrufen.

Ja, das bist Du.

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

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

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

Sie haben einen const-Zeiger auf ein nicht-const-Objekt mit einem non-const-Zeiger auf ein const-Objekt verwechselt.

Trotzdem

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

Es ist legal, beide zu löschen, aus den Gründen, die bereits in den anderen Antworten hier angegeben sind.

Oktalist
quelle
5

Eine andere Sichtweise: Die genaue Bedeutung eines const-Zeigers besteht darin, dass Sie keine Änderungen an dem Objekt vornehmen können, auf das verwiesen wird, das über diesen oder einen anderen Zeiger oder Verweis auf dasselbe Objekt sichtbar wäre. Wenn ein Objekt zerstört wird, sind alle anderen Zeiger auf die Adresse, die zuvor vom jetzt gelöschten Objekt belegt wurde, keine Zeiger mehr auf dieses Objekt . Sie speichern dieselbe Adresse, aber diese Adresse ist nicht mehr die Adresse eines Objekts (tatsächlich kann sie bald als Adresse eines anderen Objekts wiederverwendet werden).

Diese Unterscheidung wäre offensichtlicher, wenn sich Zeiger in C ++ wie schwache Referenzen verhalten würden, dh sobald das Objekt zerstört wird, würden alle vorhandenen Zeiger darauf sofort auf gesetzt 0. (Dies wird zur Laufzeit als zu kostspielig angesehen, um es allen C ++ - Programmen aufzuerlegen, und tatsächlich ist es unmöglich, es vollständig zuverlässig zu machen.)

UPDATE : Neun Jahre später ist es anwaltlich. Ich finde jetzt Ihre ursprüngliche Reaktion verständlich. Mutation zu verbieten, aber Zerstörung zuzulassen, ist eindeutig problematisch. Der implizite Vertrag von const-Zeigern / Referenzen besteht darin, dass ihre Existenz als Block bei der Zerstörung des Zielobjekts fungiert, auch bekannt als automatische Speicherbereinigung.

Die übliche Lösung besteht darin, stattdessen fast jede andere Sprache zu verwenden.

Daniel Earwicker
quelle
Wenn Sie keine Dinge zerstören können, auf die durch Zeiger auf const hingewiesen wird, wie gehen Sie mit einem std::unique_ptr<const T>Ende des Lebens um?
Caleth
@Caleth dann gäbe es in C ++ keine Lösung dafür. Dies ist nur ein Beispiel für das allgemeine Problem: In C ++ bedeutet der const-Modifikator "Sie können das Ziel nur mutieren, wenn Sie es vollständig zerstören und alle anderen Verweise darauf ungültig machen und undefiniertes Verhalten verursachen". Aus diesem Grund denke ich, dass diese Art von Frage als Aufforderung dienen sollte, andere Sprachen in Betracht zu ziehen. Es enthält UB-Löcher, die nicht ohne einen anderen grundlegenden Ansatz gelöst werden können.
Daniel Earwicker