The "delete array" operator in C++, and cause for infinite amounts of incorrect code which appears to work erratically. Indeed, delete[] (yes, it really is spelled like that, complete with empty square brackets!) could easily have qualified for its own freakshow node, had it only already existed on E2. As it stands, my insults will have to be mixed with a modicum of information.

As may have been guessed by the first sentence, delete[] exists to delete arrays of objects. You allocate an array of objects of type C by saying

unsigned int how_many = something;
C* p = new C[how_many];
When you're done with them, you get rid of the array by saying
delete[] p;

It's all remarkably similar to the malloc()/free() combo of C:

C *p;
/* ... */
p = malloc(how_many * sizeof(*p));
/* ... */
The C allocator knows how large a block it gave out, so there is no need to pass the size of the block when freeing it. The same is true for delete[], of course.

But how is this different from the use of delete? After all, in C++ you'd say

C* p = new C;
// ...
delete p;
and in C you'd still say
C *p;
/* ... */
p = malloc(sizeof(*p));
/* ... */
What's more, C++ needs operators (which are part of the language syntax), whereas C just requires library functions (which are just part of a standard library). WHY?

Recall that a C++ object is more than just a C struct with some methods and some hidden elements. Objects have constructors and destructors, which must be called at appropriate times. Now clearly, when you call either form of new, the compiler will have to generate a call to a memory allocator (which could even be malloc), then construct each of the allocated objects.

But what happens when you wish to free the memory? In fact, in C++ you're not just freeing the memory; you're getting rid of the objects and of the space they take up. Because of the ambiguity C++ inherits from C between pointers to objects and pointers to the first object in an array of object, the compiler could not tell whether the form "delete p;" refers to the destruction of a single object at which p points, or to the destruction of an entire array. So the former is chosen for this form, and delete[] p; is chosen for the second form.

If you fail to heed this distinction, things may appear to work in a particular implementation. (Of course, destructors might not get called, but most objects don't have any destructive behavior beyond freeing memory, so maybe you just get a memory leak). On the other hand, some implementation may choose to allocate arrays on a different heap from single objects; this will cause catastrophic failure. In general, using the wrong delete is much worse than using the wrong fork; it guarantees undefined behavior, which means anything might happen.

In fact, things are a bit more complex than the distinction hinted above. After all, the compiler knows what sizeof *p is in delete p;, and the library knows the size of the block of memory to which p points. By dividing the second by the first, it would appear we can get the number of objects to which p points, and consequently call the destructor for each object. In fact, we cannot. If p actually points at a derived class of C, then it points at an object (or an array of objects) whose size(s) need not be sizeof *p. If C is a class with RTTI, even this might be surmountable. But since this is not always the case, even this route for getting the delete/delete[] distinction fails. Of course, if the destructor ~C is not virtual, it will tend to call the wrong destructor. Except that the wrong destructor might be still be the right one. And C++ always assumes you know what you're doing. So we must have both deletes in the language...

Log in or register to write something here or to contact authors.