Is There Any Danger in Calling Free() or Delete Instead of Delete[]

Is there any danger in calling free() or delete instead of delete[]?

It's undefined behaviour (most likely will corrupt heap or crash the program immediately) and you should never do it. Only free memory with a primitive corresponding to the one used to allocate that memory.

Violating this rule may lead to proper functioning by coincidence, but the program can break once anything is changed - the compiler, the runtime, the compiler settings. You should never rely on such proper functioning and expect it.

delete[] uses compiler-specific service data for determining the number of elements. Usually a bigger block is allocated when new[] is called, the number is stored at the beginning and the caller is given the address behind the stored number. Anyway delete[] relies on the block being allocated by new[], not anything else. If you pair anything except new[] with delete[] or vice versa you run into undefined behaviour.

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

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.

Why does calling free () on a pointer allocated with 'new' cause heap corruption?

C++ wants to call a destructor on the object when you use delete, but passing it to free doesn't allow this to happen. If the object contained other objects then those objects' destructors would not be called either. If the object had pointers in it then those wouldn't get freed.

Additionally C++'s new and delete could actually request a larger amount of memory from malloc and use the extra for book keeping (like storing the address of the destructor function), and so the pointer you passed to free would not actually be one that was malloced.

Why [] is used in delete ( delete [] ) to free dynamically allocated array ?

Scott Meyers says in his Effective C++ book: Item 5: Use the same form in corresponding uses of new and delete.

The big question for delete is this: how many objects reside in the memory being deleted? The answer to that determines how many destructors must be called.

Does the pointer being deleted point to a single object or to an array of objects? The only way for delete to know is for you to tell it. If you don't use brackets in your use of delete, delete assumes a single object is pointed to.

Also, the memory allocator might allocate more space that required to store your objects and in this case dividing the size of the memory block returned by the size of each object won't work.

Depending on the platform, the _msize (windows), malloc_usable_size (linux) or malloc_size (osx) functions will tell you the real length of the block that was allocated. This information can be exploited when designing growing containers.

Another reason why it won't work is that Foo* foo = new Foo[10] calls operator new[] to allocate the memory. Then delete [] foo; calls operator delete[] to deallocate the memory. As those operators can be overloaded, you have to adhere to the convention otherwise delete foo; calls operator delete which may have an incompatible implementation with operator delete []. It's a matter of semantics, not just keeping track of the number of allocated object to later issue the right number of destructor calls.

See also:

[16.14] After p = new Fred[n], how does the compiler know there are n objects to be destructed during delete[] p?

Short answer: Magic.

Long answer: The run-time system stores the number of objects, n, somewhere where it can be retrieved if you only know the pointer, p. There are two popular techniques that do this. Both these techniques are in use by commercial-grade compilers, both have tradeoffs, and neither is perfect. These techniques are:

  • Over-allocate the array and put n just to the left of the first Fred object.
  • Use an associative array with p as the key and n as the value.

EDIT: after having read @AndreyT comments, I dug into my copy of Stroustrup's "The Design and Evolution of C++" and excerpted the following:

How do we ensure that an array is correctly deleted? In particular, how do we ensure that the destructor is called for all elements of an array?

...

Plain delete isn't required to handle both individual objects an arrays. This avoids complicating the common case of allocating and deallocating individual objects. It also avoids encumbering individual objects with information necessary for array deallocation.

An intermediate version of delete[] required the programmer to specify the number of elements of the array.

...

That proved too error prone, so the burden of keeping track of the number of elements was placed on the implementation instead.

As @Marcus mentioned, the rational may have been "you don't pay for what you don't use".


EDIT2:

In "The C++ Programming Language, 3rd edition", §10.4.7, Bjarne Stroustrup writes:

Exactly how arrays and individual objects are allocated is implementation-dependent. Therefore, different implementations will react differently to incorrect uses of the delete and delete[] operators. In simple and uninteresting cases like the previous one, a compiler can detect the problem, but generally something nasty will happen at run time.

The special destruction operator for arrays, delete[], isn’t logically necessary. However, suppose the implementation of the free store had been required to hold sufficient information for every object to tell if it was an individual or an array. The user could have been relieved of a burden, but that obligation would have imposed significant time and space overheads on some C++ implementations.

delete vs delete[] operators in C++

The delete operator deallocates memory and calls the destructor for a single object created with new.

The delete [] operator deallocates memory and calls destructors for an array of objects created with new [].

Using delete on a pointer returned by new [] or delete [] on a pointer returned by new results in undefined behavior.

Is delete this a bad idea?

The FAQlite answers this quite well:

As long as you're careful, it's OK for
an object to commit suicide (delete
this).

Here's how I define "careful":

  1. You must be absolutely 100% positive sure that this object was
    allocated via new (not by new[], nor
    by placement new, nor a local object
    on the stack, nor a global, nor a
    member of another object; but by plain
    ordinary new).
  2. You must be absolutely 100% positive sure that your member
    function will be the last member
    function invoked on this object.
  3. You must be absolutely 100% positive sure that the rest of your
    member function (after the delete this
    line) doesn't touch any piece of this
    object (including calling any other
    member functions or touching any data
    members).
  4. You must be absolutely 100% positive sure that no one even touches
    the this pointer itself after the
    delete this line. In other words, you
    must not examine it, compare it with
    another pointer, compare it with NULL,
    print it, cast it, do anything with
    it.

Naturally the usual caveats apply in
cases where your this pointer is a
pointer to a base class when you don't
have a virtual destructor.

Basically, you need to take the same care as you do with deleteing any other pointer. However, there are more areas where things can go wrong with a member function committing suicide, compared with an explicitly-declared pointer.

What's the result if I use delete p instead of delete [] p for an array?

It is undefined behavior.

What this means is that the standard gurantees to the writers of the memory management library that certain pre-conditions exist (In this case that arrays will be deleted with delete []).

If you break these pre-conditions then the memory management library could fail in some way. How it fails will depend on how the library is implemented. But since C++ is designed for speed the result is probably not going to be nice. So usually this means that the internal memory management data structures are corrupted in some way. This will probably lead to some other part of your program sigfaulting.

If you build in debug mode (on some compilers) they will use a special version of the memory management library that is designed to be more robust. Thus in these situations you may not crash but the extra checks have been explicitly added to the library and as a result is slower. But you still can not gurantee correct behavior.

Is delete[] equal to delete?

Whether this leads to a memory leak, wipes your hard disk, gets you pregnant, makes nasty Nasal Demons chasing you around your apartment, or lets everything work fine with no apparent problems, is undefined. It might be this way with one compiler, and change with another, change with a new compiler version, with each new compilation, with the moon phases, your mood, or depending on the number of neutrinos that passed through the processor on the last sunny afternoon. Or it might not.

All that, and an infinite number of other possibilities are put into one term: Undefined behavior:

Just stay away from it.



Related Topics



Leave a reply



Submit