The C++ standard very clearly and explicitly states that using delete
or delete[]
on a void
-pointer is undefined behavior, as quoted in this answer:
This implies that an object cannot be deleted using a pointer of type
void*
because there are no objects of typevoid
.
However, as I understand it, delete
and delete[]
do just two things:
- Call the appropriate destructor(s)
- Invoke the appropriate
operator delete
function, typically the global one
There is a single-argument operator delete
(as well as operator delete[]
), and that single argument is void* ptr
.
So, when the compiler encounters a delete-expression with a void*
operand, it of course could maliciously do some completely unrelated operation, or simply output no code for that expression. Better yet, it could emit a diagnostic message and refuse to compile, though the versions of MSVS, Clang, and GCC I've tested don't do this. (The latter two emit a warning with -Wall
; MSVS with /W3
does not.)
But there's really only one sensible way to deal with each of the above steps in the delete operation:
void*
specifies no destructor, so no destructors are invoked.void
is not a type and therefore cannot have a specific correspondingoperator delete
, so the globaloperator delete
(or the[]
version) must be invoked. Since the argument to the function isvoid*
, no type conversion is necessary, and the operator function must behavior correctly.
So, can common compiler implementations (which, presumably, are not malicious, or else we could not even trust them to adhere to the standard anyway) be relied on to follow the above steps (freeing memory without invoking destructors) when encountering such delete expressions? If not, why not? If so, is it safe to use delete
this way when the actual type of the data has no destructors (e.g. it's an array of primitives, like long[64]
)?
Can the global delete operator, void operator delete(void* ptr)
(and the corresponding array version), be safely invoked directly for void*
data (assuming, again, that no destructors ought to be called)?
struct S {int i;} s; s.i=1;
violates a runtime constraint since it uses an lvalue or glvalue of typeint
to access astruct S
, but such behavior would be sufficiently obviously absurd that even the authors of gcc and clang would recognize it as stupid. – Comber