🔒 Locked
delete [] question
Advertisement
Original Post
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?
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).
then what's the solution?
delete [] (Derived *)b; //does this work?
delete [] (Derived *)b; //does this work?
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.
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?
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?
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.
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.
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
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
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.
Quote:
Original post by SiCrane
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.
I'm making that my sig.
Topic Locked
This topic has been locked by a moderator. New replies are not allowed.
Sign in to reply to this topic.
Advertisement