First of all, using delete
for anything allocated with new[]
is undefined behaviour according to C++ standard.
In Visual C++ 7 such pairing can lead to one of the two consequences.
If the type new[]'ed has trivial constructor and destructor VC++ simply uses new
instead of new[]
and using delete
for that block works fine - new
just calls "allocate memory", delete
just calls "free memory".
If the type new[]'ed has a non-trivial constructor or destructor the above trick can't be done - VC++7 has to invoke exactly the right number of destructors. So it prepends the array with a size_t
storing the number of elements. Now the address returned by new[]
points onto the first element, not onto the beginning of the block. So if delete
is used it only calls the destructor for the first element and the calls "free memory" with the address different from the one returned by "allocate memory" and this leads to some error indicaton inside HeapFree() which I suspect refers to heap corruption.
Yet every here and there one can read false statements that using delete
after new[]
leads to a memory leak. I suspect that anything size of heap corruption is much more important than a fact that the destructor is called for the first element only and possibly the destructors not called didn't free heap-allocated sub-objects.
How could using delete
after new[]
possibly lead only to a memory leak on some C++ implementation?
Suppose I'm a C++ compiler, and I implement my memory management like this: I prepend every block of reserved memory with the size of the memory, in bytes. Something like this;
| size | data ... |
^
pointer returned by new and new[]
Note that, in terms of memory allocation, there is no difference between new
and new[]
: both just allocate a block of memory of a certain size.
Now how will delete[]
know the size of the array, in order to call the right number of destructors? Simply divide the size
of the memory block by sizeof(T)
, where T
is the type of elements of the array.
Now suppose I implement delete
as simply one call to the destructor, followed by the freeing of the size
bytes, then the destructors of the subsequent elements will never be called. This results in leaking resources allocated by the subsequent elements. Yet, because I do free size
bytes (not sizeof(T)
bytes), no heap corruption occurs.