Violet Giraffe Violet Giraffe - 3 months ago 8
C++ Question

Why does calling delete instead of delete[] on an array of class objects cause heap corruption?

Consider the code:

class A {
public:
virtual ~A() {}
};

class B : public A {
public:
~B() {}
};

void main ()
{
A * array = new A[100];
delete array;
}


On Windows (MSVC 2010), it causes exception because
delete
calls
HeapValidate
, which then indicates the heap was corrupted. How and why does this happen?

I indeed realize
delete[]
should be called here, and of course then there is no problem. But why does
delete
cause heap corruption? As far as I know, it should call a destructor for the first object (
array[0]
or
*array
) and then free the whole block. What happens in reality?

Note: if class
A
only has default destructor, i.e. I don't declare its destructor at all, the exception does not occur. Regardless of whether the destructor is virtual or not. Both in debug and release build.

P. S. yes I know this is undefined behavior.

Answer

It is undefined behavior to call delete on a pointer created with new[]. The basic issue is that when you call new[] it needs to allocate extra space to store the number of elements in the array, so that when you call delete [] it knows how many elements to destroy.

The library will allocate space for the management data in addition to the needed space for the real objects. It will then perform all initialization and return a pointer to the first element, which is not aligned with the block of memory retrieved from the OS.

[header][element1,element2...]
^       ^
|       \_ pointer returned by new[]
|
\_ pointer returned by the allocator

On the other hand, new and delete don't store any extra information.

When you call delete[] it moves the pointer back, reads the count, calls the destructors and deallocates using the original pointer. When you call delete, it calls the destructor for the single object and passes the pointer back to the allocator. If the pointer was created through a call to new[], then the pointer that is returned to the allocator is not the same pointer that was allocated and the deallocation fails.

Comments