delete auf T const*
-
Schon wieder eine blöde Frage:
Ist es eigentlich definiert,deleteauf einen Zeiger auf konstante Objekte anzuwenden?
Beispiel:int const* pi = new int(42); delete pi; //definiert?Im Standard habe ich dazu irgendwie nichts gefunden, und Quellen im Netz sind irgendwie widersprüchlich. Auf gängigen modernen Compilern compiliert es anstandslos. Auf älteren MS-Compiler gibt es den Fehler:
Error C2710:cannot delete a pointer to a const object.PS: Vom Gefühl her würde ich sagen, dass es nicht definiert ist, weil ja delete den Zustand des Objektes ändert.
-
const bedeutet ja nicht dass der Zustand des Objekts nicht geändert werden darf. Es gibt ja schliesslich mutable (und const_cast). Und Zeiger (mit denen man dasselbe erreichen kann wie mit mutable).
Was const für Klassen wirklich bedeutet, definiert derjenige, der eine Klasse schreibt. Für die "eingebauten" Typen is es natürlich klar.
Und ich würde auch nicht sagen dass delete den Zustand von irgendwas ändert. Vorher isses da, nachher isses nichtmehr da. Was nichtmehr da ist, kann keinen Zustand haben, also kann sich der Zustand auch nicht geändert haben. Nen?
Und warum es Sinn macht? Schonmal alleine wegen der Symmetrie zu nicht-statischen const Membern einer Klasse:
class X { public: X() : m_foo(make_foo_string()) {} const std::string m_foo; // darf sich nie ändern während X existiert, also machen wir es const. // das ist praktisch, weil der compiler schreit, wenn man versuchen würde m_foo trotzdem zu ändern! }; void test() { X* x = new X(); delete x; // hier lösche ich effektiv einen "const std::string". }----
Ein konkreter Anwendungsfall, wo es wirklich gut ist, dass man Objekte über einen const Zeiger löschen kann (das Objekt kann selbst ja niemals const sein, wenn man es über new erzeugt hat), ist intrusive reference counting:
class Y { public: void add_ref() const { ... } void release() const { ... if (...) delete this; // hier hätten wir ein problem wenn wir nicht über const zeiger löschen dürften } private: mutable size_t m_refs; };Wären wir nun gezwungen die release() Funktion nicht-const zu machen, dann könnten wir keine const Zeiger auf Y an Funktionen/Programmteile übergeben, die den Reference-Counting-Mechanismus von Y verwenden möchten. Wäre irgendwie doof ... weil const halt praktisch ist, und man es dann an einigen Stellen nichtmehr verwenden könnte.
-
hustbaer schrieb:
...
Das ist gut. Es macht auch wirklich Sinn, wenn ich so über das von Dir geschriebene nachdenke.
Danke.

-
hustbaer schrieb:
const bedeutet ja nicht dass der Zustand des Objekts nicht geändert werden darf. Es gibt ja schliesslich mutable
Jein. Mutable Member gehören nicht zum Zustand der Klasse. Und const_cast bei konstanten Objekten ist böse. Ist Sache des Standpunkts des Betrachters. Von der Programmlogik her heißt const "nicht anfassen". Aus Compilersicht kann man const wegcasten und schauen was passiert, wenn man sich Mühe gibt frisst der Compiler fast alles...
[cquote]Und ich würde auch nicht sagen dass delete den Zustand von irgendwas ändert. Vorher isses da, nachher isses nichtmehr da. Was nichtmehr da ist, kann keinen Zustand haben, also kann sich der Zustand auch nicht geändert haben. Nen?[/quote] Exakt. Bei Betreten des Destruktors hat die Lebenszeit des Objektes bereits aufgehört. Damit ist kein Zustand mehr vorhanden und es kann passieren was will. Deshalb gibts auch keine const-Destrutkoren, und in Destruktoren können die Member bei Bedarf doch wieder geändert werden. Gleiches gilt allerdings für den Ctor - die Lebenszeit eines Objektes und damit der Zustand beginnt erst bei Verlassen des Ctors.
(das Objekt kann selbst ja niemals const sein, wenn man es über new erzeugt hat)
Doch, es kann. Während des Aufrufs von new gibts noch kein fertiges Objekt das const sein könnte. Folgendes funktioniert bei mir ohne Beschwerden:
class X { int i; public: X() : i(5) { i = 6 ;} ~X() { i = 7;} }; int main() { X const* xp = new X(); delete xp; cout << "Geht doch!" << endl; }
-
pumuckl schrieb:
hustbaer schrieb:
const bedeutet ja nicht dass der Zustand des Objekts nicht geändert werden darf. Es gibt ja schliesslich mutable
Jein. Mutable Member gehören nicht zum Zustand der Klasse. Und const_cast bei konstanten Objekten ist böse. Ist Sache des Standpunkts des Betrachters. Von der Programmlogik her heißt const "nicht anfassen". Aus Compilersicht kann man const wegcasten und schauen was passiert, wenn man sich Mühe gibt frisst der Compiler fast alles...
Ich weiss schon was du meinst. Ich meinte bloss: der C++ Standard liefert zwar viele deutliche Hinweise darauf, wie const zu verwenden ist... (die Semantik bei eingebauten Typen sowie Typen der Standard-Library, das Keyword heisst "const" und nicht "foo" oder sonstwie). Dennoch schreibt er keine genaue Interpretation/Bedeutung für UDTs vor.
Wenn ich möchte, bastle ich mir eine Klasse für einen Kartenstabel (Spielkarten), und definiere "const" dann so, dass man zwar Karten abheben kann, den Stapel aber nicht mischen. Oder ich mache eine Stream-Klasse, aus der man zwar über const lesen kann (und damit den "Stream-Pointer" verschieben, also durchaus den State verändern), aber nix schreiben kann. Oder wozu ich halt grad lustig bin.
Natürlich wäre das mit dem Kartenstapel total plem, aber der Standard sagt nicht dass das verboten oder böse wäre. Das mit dem Stream ist vermutlich auch keine gute Idee, weil man es besser über Interface-Klassen (ReadStream, WriteStream) lösen könnte.Ich würde es eher so formulieren: man sollte sich bei "const" an das "Principle of least astonishment" denken. (Und nicht nur bei "const")
Und wenn man das tut, dann verbieten sich natürlich diverse exotischere Interpretationen.Und ich würde auch nicht sagen dass delete den Zustand von irgendwas ändert. Vorher isses da, nachher isses nichtmehr da. Was nichtmehr da ist, kann keinen Zustand haben, also kann sich der Zustand auch nicht geändert haben. Nen?
Exakt. Bei Betreten des Destruktors hat die Lebenszeit des Objektes bereits aufgehört. Damit ist kein Zustand mehr vorhanden und es kann passieren was will. Deshalb gibts auch keine const-Destrutkoren, und in Destruktoren können die Member bei Bedarf doch wieder geändert werden. Gleiches gilt allerdings für den Ctor - die Lebenszeit eines Objektes und damit der Zustand beginnt erst bei Verlassen des Ctors.
Jo. Da sind wir uns ja einig, wenn ich dich richtig verstehe...

(das Objekt kann selbst ja niemals const sein, wenn man es über new erzeugt hat)
Doch, es kann. Während des Aufrufs von new gibts noch kein fertiges Objekt das const sein könnte. Folgendes funktioniert bei mir ohne Beschwerden:
class X { int i; public: X() : i(5) { i = 6 ;} ~X() { i = 7;} }; int main() { X const* xp = new X(); delete xp; cout << "Geht doch!" << endl; }Er, nein. Denkfehler.
Das Objekt der Klasse X ist hier NICHT const. "new X()" erzeugt das Objekt. Wo ist da ein const? Dass du den Returnwert von "new X()" dann in einem "Zeiger auf const" ablegst ist hier überhaupt nicht relevant. Der Punkt ist: es gibt nicht bloss keine const DEstruktoren, es gibt auch keine const KONstruktoren. Damit kann ein Objekt welches einen Ctor hat NIEMALS wirklich const sein. Genaugenommen nichtmal dann, wenn es global/statisch instanziert wird.In deinem Beispiel ist bloss der Zeiger auf dein Objekt ein "const-Zeiger". Das bedeutet weiter, dass du in diesem Beispiel das const ohne weiteres wegcasten dürftest, ohne dass es hier zu UB kommen darf.