Deleting a Pointer to Const (T Const*)

Deleting a pointer to const (T const*)

It's to support:

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

// use const member functions here

// delete it
delete f;

But note that the problem is not limited to dynamically created objects:

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

If destructors could not be called on const objects we could not use const objects at all.

How does delete deal with pointer constness?

const_cast doesn't really do anything – it's a way to suppress compiler moaning about const-ness of the object. delete keyword is a compiler construct, the compiler knows what to do in this case and doesn't care about const-ness of the pointer.

Was the behavior of deleting pointers-to-const changed in the past?

You can indeed delete a pointer-to-const.

If Visual C++ says otherwise for a standard-conforming program, then that's a compiler bug and should be reported.

Your (or Microsoft's?) program is not standard C++, however, since you have void result type for main.

The KB article you link to says "Deleting a pointer to a constant should not be allowed by definition (ARM section 5.3.4)", and although it's wrong, the reference it gives is correct. The ARM section 5.3.4 says "A pointer to constant cannot be deleted". However, the ARM was published in 1990...

C++ was standardized about ten years later, in 1998, and in standard C++ you can delete a pointer to const. This is not specified in the normative text; it's specified by omitting the restriction. However, the C++98 standard §5.3.5/2 has the following non-normative note:

a pointer to a const type can be the operand of a delete-expression; it is not necessary to cast away the constness (5.2.11) of the pointer expression before it is used as the operand of the delete-expression.

We are now over ten years after that standardization again, over 20 years after the ARM.

Which version of Visual C++ are you using?

Cheers & hth.,

Why can delete operator be used in const context?

So I think delete p; may change the member p of rhs though rhs is a const reference.

  1. No. delete p; doesn't change p. Invalidation is not modification.

  2. Regardless, having a const reference to an object (rhs) does not by any means prevent the referred object form being modified. It merely prevents modification through the const reference. In this case we access the object through this which happens to be a pointer to non-const, so modification is allowed.

Someone may insist that "to render a pointer invalid is not to change the value of a pointer" but I don't find such a statement in the standard.

The behaviour of delete expression is specified in [expr.delete]. Nowhere in that section does it mention that the operand is modified.

Becoming invalid is specified like this:

[basic.compound]

... A pointer value becomes invalid when the storage it denotes reaches the end of its storage duration ...

Note that it is the value that becomes invalid. The pointer still has the same value because the pointer was not modified. The value that the pointer had and still has is simply a value that no longer points to an object - it is invalid.



Supplement: I've changed delete p; to delete rhs.p;, but it still works. Why?

Answer 2. From previous question no longer applies, but answer 1. does. delete rhs.p; does not modify rhs.p.

Why delete can perform on pointers to const while free cannot?

free should not be used with actual C++ objects. free should be used with malloc, so you shouldn't be using free on something you allocated with new.

As to why you can delete const objects, that's simple:

const Type *ptr = new Type(...);

Now what? If you couldn't delete that, then you'd have to do this:

delete const_cast<Type*>(ptr);

Having an object be const means that it cannot be modified. You cannot cause the object to go from one state to another state. Deletion is throwing it away. Meaning that it no longer exists in any state, whether the original one or some other modified form. Deletion is an operation that exists outside of the object's mutability state, much like construction.

Conceptually, deletion is neither const nor non-const. While a destructor is a non-const function, the idea of destructing an object is simply outside the domain of const or non-const.


OK, let's say you define operator delete to take a pointer to const (which is different from a const pointer):

void operator delete(void const* p);

What is the first line of this function going to be? The purpose of operator delete is to free memory that was allocated by operator new. That will require poking at bits on the memory allocation heap. And to do that, you need a pointer that does not point to const data:

void *ptr = const_cast<void*>(p);

Welcome to undefined behavior. While C++ allows you to do this, the specification is very clear that the results of attempting to write to ptr (or any address based on it) are undefined. You were given a const pointer; you were told by the outside world not to modify the stuff it pointed to. C++ provides no guarantees about what happens when you break that contract.

Since the specification states that this is undefined behavior, and since operator delete (in most cases) cannot do its job without modifying the memory pointed to by p (or modifying memory based on that address), it would be silly of the specification to then allow you to define operator delete this way. It would basically be canonizing the idea of shooting yourself in the foot.

Yes, in virtually every case, this would be completely safe. But since you're going to cast away the const anyway, why even bother to allow the rather dubious idea in the first place?

Is it a good practice to free memory via a pointer-to-const

Well, here's some relevant stuff possibly too long to fit into a comment:

  1. Some time ago the practice to free memory via a pointer-to-const was plain forbidden, see this dr. Dobb's article, the "Language Law" ( :)) part.

  2. There has twice been a relevant discussion on http://groups.google.ru/group/comp.lang.c++.moderated: "Delete a const pointer?", "Why can operator delete be called on a const pointer" (both actually deal with the case in question, i.e. pointer to const).

  3. My own point (since you are asking for arguments): possibility of the operation in question in any given context is defined by the (explicitly or implicitly defined in the documentation) contract of a class or a function, not by just the method signature or parameter types.

Why a const T* is trivially converted to void* in operator delete ?

While I quite agree with @JamesKanze's answer, perhaps somebody would like to see what the standard actually says. According to the standard (§12.1/4):

const and volatile semantics (7.1.5.1) are not applied on an object under
construction. Such semantics only come into effect once the constructor for the most derived object (1.8)
ends.

and (§12.4/2):

const and
volatile semantics (7.1.5.1) are not applied on an object under destruction. Such semantics stop being
into effect once the destructor for the most derived object (1.8) starts.

In fairness, this does little more than re-state what @James said, a bit more specifically: the object is only really considered an object from the time the ctor finishes (or all the ctors, when inheritance is involved) to the point that the first dtor begins. Outside those boundaries, const and volatile aren't enforced.

remove const from a typedef datatype

You can define a template function that is overloaded for pointers:

template <typename T>
T& remove_const(const T& value)
{
return const_cast<T&>(value);
}

template <typename T>
T* remove_const(const T* value)
{
return const_cast<T*>(value);
}

And call it as so:

std::array<const uint8_t, 8> buf = {'\0'};

BufType cdata = buf.data();
uint8_t* data = remove_const(data);

If you want a way to express the resulting type, i.e. remove the const of the pointed-to type, you could define a type trait like this (or define template specializations, as in the function case):

template <typename T>
struct remove_pointed_to_const
{
using type = std::add_pointer_t<std::remove_const_t<std::remove_pointer_t<T>>>;
};

// This static_assert is correct.
static_assert(std::is_same<remove_pointed_to_const<BufType>::type, uint8_t*>::value);

In this alternative, you could use const_cast directly at the point of use, which might make it easier to identify all const_cast locations in a project:

std::array<const uint8_t, 8> buf = {'\0'};  
BufType const cdata = buf.data();
uint8_t* data = const_cast<remove_pointed_to_const<BufType>::type>(data);

As a comment said, and as with all const_cast usages, you need to be careful not to apply this to an object that was initialized as a const object. Doing so would be UB.



Related Topics



Leave a reply



Submit