Sign in to follow this  

delete [] question

This topic is 4712 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

let Derived be a class that derives from class Base. now if I do this: Base *b = new Derived[10]; and later I do this: delete [] b; will the above delete[] properly release the memory allocated by new? how does it know to delete 10 Base or 10 Derived?

Share this post


Link to post
Share on other sites
Quote:
Original post by digitalfreak
will the above delete[] properly release the memory allocated by new?


The memory allocated for the array itself will be deallocated correctly. But...

Quote:
how does it know to delete 10 Base or 10 Derived?


It doesn't know.

Treating arrays polymorphically is a big no-no.

The compiler uses the (static) type of the pointer to determine how far aparts objects are located in the array. If Base and Derived have different sizes, delete[] will use the wrong offsets when calling the destructors.

For the destructors themselves, it relies on the virtual function table. Which is why, if you are going to delete a Derived object through a pointer to Base, Base need a virtual destructor. Of course, it is contingent on finding the objects in the expected places (see previous paragraph).

Share this post


Link to post
Share on other sites
No, it doesn't. You should either:


Derived *d = new Derived [10];
...
delete [] d;



or:


Base **b = new Base * [10];
for (int i = 0; i < 10; ++i) b [i] = new Derived;
...
for (int i = 0; i < 10; ++i) delete b [i];
delete [] b;

Share this post


Link to post
Share on other sites
Quote:
Original post by digitalfreak
then what's the solution?
delete [] (Derived *)b; //does this work?

Actually this will work, but you shouldn't do it. It will work only if you know b *definately* points to an array of Derived.....in which case you should be using Kippesoep's first example anyway.

Share this post


Link to post
Share on other sites
hi, I've just checked this with vc++ 2003.net
I watched the memory holding the array before and after delete, I could tell that the exact amount of memory that were allocted by new were released, no matter I use (Derived *) coercion or not.

so what does this imply?

Share this post


Link to post
Share on other sites
This would imply either Base and Derived are the same size, or you code was simple enough for the compiler to know what to do.

What were the sizes of Base and Derived?

Share this post


Link to post
Share on other sites
According to the C++ standard (Section 5.3.5 paragraph 3 for those of you keeping track at home) using delete [] on a pointer whose dynamic type differs from its static type has undefined behaviour. And undefined behaviour can mean cleaning up the memory properly and calling all of right the destructors.

It can also mean segfaulting and launching nuclear missiles at a cow ranch in Alaska.

However, judging from the generated disassembly, in a new project, with default compiler settings, etc. as long as the base class's destructor is virtual, MSVC 7.1 will free the proper amount of memory and call the right destructors. It's still not something I would rely on.

Share this post


Link to post
Share on other sites
As André LaMothe says on a similar subject, Although not COM objects are currently released automatically, not releasing COM objects might in the future create wormholes next to your head, to let's be on the safe side and release our COM objects.

Share this post


Link to post
Share on other sites
While the behavior of C++ when deleting a derived object through a base pointer may be undefined, the actual memory deallocation should work correctly. This does not, however, mean that the right destructors will be called.

C++ depends on a virtual memory allocator to satisfy requests for memory. The memory allocator returns blocks of at least the requested size or returns an error. Often, the region of memory returned is actually larger than requested so that it ends on a specific boundary (such as 8 bytes). The memory allocator tags each chunk of memory with a size value so that it knows how large each chunk is. When delete is called, the size value in the tag is used to determine how much memory must be deallocated not the size of the base or the derived object.

After the memory is deallocated, the chunk is placed in a free list of available blocks. In the GNU libc malloc implementation, each chunk of memory is tagged with the size of the current and the previous blocks. When the chunk is unallocated, a forward and back pointer are also stored in the chunk (after the size values) so that the chunk can be stored in doubly-linked list of free blocks. On allocation, the pointer values are not needed (it's not in the list anymore) so they are considered to be a part of the data region of the chunk.

Implementations of new and delete are more complicated than malloc and free because they must determine which constructors and destructors to call but the actual memory allocation should be very similar.

Steven

Share this post


Link to post
Share on other sites
Quote:
Original post by unicityd
While the behavior of C++ when deleting a derived object through a base pointer may be undefined, the actual memory deallocation should work correctly.

Don't count on it. Consider this code:

class EmptyClass {};

class BadIdea : public EmptyClass {
public:
virtual ~BadIdea() {}
};

int main(int, char **) {
EmptyClass * ptr = new BadIdea[10];
delete [] ptr;

return 0;
}

Many, if not most, C++ compilers will attempt to deallocate the wrong memory address with this code snippet, which either corrupts the heap or just causes a debug assertion as the case may be.

Undefined behavior also can mean that it won't even deallocate the memory properly.

Quote:

When delete is called, the size value in the tag is used to determine how much memory must be deallocated not the size of the base or the derived object.

That assumption is predicated on the compiler being able to correctly extract the correct pointer to pass back to the memory manager. On some compilers, with some inheritance relationships, like the above example, the compiler may not be able to do so.

Share this post


Link to post
Share on other sites

This topic is 4712 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this