First, maybe in Windows and other OSes it's different, but I've implemented these operators for a kernel. malloc and free creates a header and footer around the allocated memory, and from these it knows how much should it use, how much to free, and it's also good for error checking.
So, new is different, because it calls the constructors too. For a single (non-array) new, it creates the memory(with footer/header) and "copies" the constructed member to that location. For free/delete, it firstly checks the header/footer, delete calls destructors then deallocates the memory, e.g with free (mark it as free in a bitmap, and remove the header/footer).
If you call a single delete on an array, it tries to deallocate that only element, but because it only sees the header/or nothing, because the header is only at the beginning of the memory, it will fail, or will not destruct the objects, just deallocate the memory. This can lead to memory leaks.
E.G:
1 2
|
CLASS* obj = new CLASS;
CLASS* obj2 = new CLASS;
|
memory layout:
header_memoryobj_footer header_memoryobj2_footer
CLASS* obj = new CLASS[2];
header_memoryobj[0]_memoryobj[1]_footer