Is it possible to prevent `delete` on a `const *`?
-
Wondering idly whether C++ allows me to prevent going
delete
on aconst Something *
?// list of pointers to things, where the things pointed to must not be changed QList<const Something *> somethings; somethings[...] = new Something; // get a pointer to one thing, where the thing pointed to cannot be changed const Something *something = somethings.at(somewhere);
All good so far. Trying to go
something->member = somesuch
gives me a compiler errorassignment of member ‘Something::member’ in read-only object
.But
delete something
is accepted. I'd like to prevent that. It does not "change" what something points to, so far as compiler is concerned. OTOH it makes*something
quite "invalid", which is a kind of change.... And if Debug it may even write into the freed pointed to area for internal reasons, which again is a kind of change.I tried
const Something *const something = somethings.at(somewhere);
This makes the
something
pointer be read-only itself. If I godelete something; something = nullptr;
it errors on the attempt to go
something = nullptr
. But, sadly for me, not on thedelete something
statement. Ifdelete pointer
took a reference and also did apointer = nullptr
itself the compiler would complain. But it does not. So the extra*const
here does not do what I would like.Anyone know a way to achieve this in C++?
-
Hi,
I think you can achieve that by declaring the delete operator of your class private or protected if you want to allow for proper subclassing.
You can then add a dedicated method to allow the destruction of these object in a more controlled manner. -
@JonB
const SomeClass *const something has two meanings:- can call only const funcs
- its address can not be changed.
delete something; does not change its address. Instead deletes the contents something points to. Still a dangled pointer;
something = nullptr; changes its address, not allowed.I guess you may try a Wrapper class
class WrapperPointer { public: WrapperPointer(int* ptr) : ptr(ptr) {} ~WrapperPointer() { // does nothing } int* get() const { /* can be used to clear pointer as well */ return ptr; } private: int* ptr{}; };
-
@SGaist said in Is it possible to prevent `delete` on a `const *`?:
declaring the delete operator of your class private or protected
Ohh, I didn't even know
delete
was an operator and you can override it.@JoeCFD
Yes, you are right about* const ptr
, that just affects its value. I wishdelete ptr
setptr
tonullptr
, then I would not be allowed todelete *const ptr
which would suit me :) -
There is still one concept I don't uderstand. I got side-tracked with the second
const
, forget that.const Foo *foo = somefunc();
-
I can't go
foo->something = somewhat
because errorconst
/read-only
, perfect. -
But I can go
delete foo
(given a standarddelete
). Why?delete
frees the memory used by the object. That's just as destructive as assigning into it. If I need a non-const
pointer for write access why don't I need that todelete
too?
-
-
You could look at constructors and destructors as "special" functions that follow slightly different set of rules than other member functions. For example did you know that delete operator is the only static member function in C++ that is called polymorphically?
You could have a philosophical take on it by saying that accessing a regular mutating member is different operation than deallocating an object as a whole, but then there's the issue of mutating destructors. You could give it a pragmatic explanation that disallowing destruction through pointer to const could lead to a situation where there's no way to delete an object without a const_cast if all you have are just pointers to const. That would be fugly. You could take a C style explanation that it just deals with memory and not access, but then there are destructors...
It is what it is is what I'm trying to say. One of the many quirks of a complicated language :)
-
@JoeCFD said in Is it possible to prevent `delete` on a `const *`?:
- can call only const funcs
delete
does not only delete the contents something points to. It also calls the destructor of the underlying object. So, there is an inconsistency that I can call the destructor on a const object (which I never noticed in my long C++ career).Best advice is to not use plain owning pointers in C++. But, that would still leave you with the convention to use raw pointers as non-owning pointers with the technical possibility that someone calls
delete
on them. Making the delete operator private works to suppress this, but is also really intrusive to be of general use. -
@SimonSchroeder said in Is it possible to prevent `delete` on a `const *`?:
It also calls the destructor of the underlying object. So, there is an inconsistency that I can call the destructor on a const object (which I never noticed in my long C++ career).
Exactly! I am "surprised" that you have never "noticed" this, as I most certainly have, and is precisely why I am so shocked it is allowed! :) I am finding this whole "you cannot change the object via
const *
but feel free to completely clobber it by deleting" very odd! -
J JonB has marked this topic as solved on
-
@JonB said in Is it possible to prevent `delete` on a `const *`?:
I am finding this whole "you cannot change the object via const * but feel free to completely clobber it by deleting" very odd!
Else, you would not be able to free the memory
-
@JonB said in Is it possible to prevent `delete` on a `const *`?:
I am finding this whole "you cannot change the object via const * but feel free to completely clobber it by deleting" very odd!
freeing an objects memory is very much different from changing its internal state. const only prohibits the later
-
@J-Hilk said in Is it possible to prevent `delete` on a `const *`?:
freeing an objects memory is very much different from changing its internal state. const only prohibits the later
Well it may be "different" but it is equally "destructive". And ends up "changing its internal state" as a consequence. Hence the discussion. I now get that "const only prohibits the later", and that's life, but I still find it "odd".
-
I was just thinking about this: Is it possible to overload the delete operator with a const and non-const version?
-
@SimonSchroeder
So for my case that would do what, presumably runtime error? I was looking for a compile-time error on attempting todelete
aconst
pointer (like I would get on attempting to write to a member/call a non-const
member method). -
@JonB said in Is it possible to prevent `delete` on a `const *`?:
So for my case that would do what, presumably runtime error?
If you can distinguish that, you could make the const-version private and the non-const public. So, you can still normally delete objects when you are allowed to (with a pointer to non-const). But I'm not sure if this distinction is possible.
-
@SimonSchroeder said:
But I'm not sure if this distinction is possible
It's not. The delete operator can't be cv qualified.
Here's a fun quirk:
struct Foo { void itIsFine() const { delete this; } ~Foo() { bar = 42; } int bar = 0; }; const Foo* foo = new Foo(); foo->itIsFine();
so not only can you delete an object through a pointer to const, but a const function can mutate the object without
mutable
orconst_cast
by deleting the object it is being called on;)