derived class deletion
category: code [glöplog]
I know this is beginner stuff but I need confirmation.
Consider the following:
struct Base
{
~Base() {}
virtual void Execute() = 0;
};
struct Derived : public Base
{
~Derived() {}
void Execute() {}
};
struct DerivedWithData : public Base
{
int mData;
~DerivedWithData() {}
void Execute() {}
};
//example 1
Base* a = new Derived;
delete a;
//example 2
Base* a = new DerivedWithData;
delete a;
Now I'm aware that the derived class destructors wont be called because the base class destructor is not virtual.
Still, are both examples leaking memory?
Or in other words, do you need a virtual destructor for the delete operator to deallocate the correct amount?
Consider the following:
struct Base
{
~Base() {}
virtual void Execute() = 0;
};
struct Derived : public Base
{
~Derived() {}
void Execute() {}
};
struct DerivedWithData : public Base
{
int mData;
~DerivedWithData() {}
void Execute() {}
};
//example 1
Base* a = new Derived;
delete a;
//example 2
Base* a = new DerivedWithData;
delete a;
Now I'm aware that the derived class destructors wont be called because the base class destructor is not virtual.
Still, are both examples leaking memory?
Or in other words, do you need a virtual destructor for the delete operator to deallocate the correct amount?
Quote:
Still, are both examples leaking memory?
yes, both destructors wont be called.
Quote:
do you need a virtual destructor for the delete operator to deallocate the correct amount?
yes ~Base() {} should be virtual.
thanks
Those particular examples won't leak memory. The destructor isn't the part of an object that frees the memory the object has been using. And delete ultimately passes a void* to free, so it will release correct amount of memory regardless.
What delete won't do is figure out the full class of the object you're deleting, so if you pass a pointer to the base class, only the base class destructor is called. That will cause a resource leak if the derived class owns resources that are supposed to be released by its destructor, such as file handles or pointers to other objects, but it makes no difference if the destructor is empty anyway and all the member variables are fundamental types like int.
If the base class destructor is virtual, though, then the destructor call happens much like a virtual method call (note that the derived class still calls the base class destructor, so you're "chaining" the destructors rather than overriding).
The general rule is that any class with virtual methods should have a virtual destructor, too. There are still cases, though, where a class without virtual methods should have a virtual destructor. On the other hand, if you always make destructors virtual to be on the safe side, there is a performance penalty.
What delete won't do is figure out the full class of the object you're deleting, so if you pass a pointer to the base class, only the base class destructor is called. That will cause a resource leak if the derived class owns resources that are supposed to be released by its destructor, such as file handles or pointers to other objects, but it makes no difference if the destructor is empty anyway and all the member variables are fundamental types like int.
If the base class destructor is virtual, though, then the destructor call happens much like a virtual method call (note that the derived class still calls the base class destructor, so you're "chaining" the destructors rather than overriding).
The general rule is that any class with virtual methods should have a virtual destructor, too. There are still cases, though, where a class without virtual methods should have a virtual destructor. On the other hand, if you always make destructors virtual to be on the safe side, there is a performance penalty.
to give an example:
THIS will leak memory.
Code:
struct Base
{
int * pBaseData;
Base() { pBaseData = new int[100]; }
~Base() { delete[] pBaseData; }
virtual void Execute() = 0;
};
struct Derived : public Base
{
~Derived() {}
void Execute() {}
};
struct DerivedWithData : public Base
{
int * pData;
DerivedWithData() { pData = new int[10]; }
~DerivedWithData() { delete[] pData; }
void Execute() {}
};
//example 1
Base* a = new Derived;
delete a;
//example 2
Base* a = new DerivedWithData;
delete a;
THIS will leak memory.
stuct's are so 1980.
Quote:
On the other hand, if you always make destructors virtual to be on the safe side, there is a performance penalty.
Then again, as soon as you notice the "performance penalty" from routing destructor calls through one level of indirection at all, you can be pretty sure you've got way, WAY bigger problems with the way you structured your code. :)
Just make all your destructor virtual and ask yourself why this isn't the default. Or rather do not. Code a demo instead.
not exactly the same, but maybe some ppl dont know about this page yet and especially that small portion of code that can help a lot:
Iterate & Delete
rest of the page is helpful for every coder aswell, thanx chaos :)
Iterate & Delete
rest of the page is helpful for every coder aswell, thanx chaos :)
well,maybe i wanted to post this first:
http://xyzw.de/c150.html
^as said, its all useful on chaos page ! ♥
http://xyzw.de/c150.html
^as said, its all useful on chaos page ! ♥
Memory Leaks
sorry, dunno if i correctly implemented the earlier post with BB, got that plugin making any link clinkable...
sorry, dunno if i correctly implemented the earlier post with BB, got that plugin making any link clinkable...
Quote:
http://xyzw.de/c150.html
Is that what windows programmers do instead of Valgrind?
Valgrind? Is that what Linux programmers do instead of having a HTTP server that shows live memory usage sorted by all kinds of criteria while the program is running at normal speed?
Quote:
An even better question is: Why do you care? :D
Still, are both examples leaking memory?
Or in other words, do you need a virtual destructor for the delete operator to deallocate the correct amount?
I guess it won't leak memory since the parent class isn't storing any actual data.
Actually, example 2 is going to leak. Example 1 is not going to leak.
http://xyzw.de/c130.html
that's a genius way of performance optimizing :O
that's a genius way of performance optimizing :O
Doom : your explanation makes sense, that's what I thought first. The internal memory manager has to keep track of the allocation size anyway.
The reason I care is because of executable size, not performance.
The reason I care is because of executable size, not performance.
duff, if you're doing size optimized coding and still need deconstructors - then you're doing it wrong. ExitProcess cleans up nicely.
Exactly. The OS is your perfect deallocator. And for your temporary stuff it gets allocated on memory pools which are deleted per-frame, per-scene etc.
duffman: What rasmus said. If you're size-coding so hard that you care about the overhead of virtual methods, you probably shouldn't be desiging class hierarchies to begin with.
Quote:
Valgrind? Is that what Linux programmers do instead of having a HTTP server that shows live memory usage sorted by all kinds of criteria while the program is running at normal speed?
That is a pretty ossom idea! Do you use custom allocators to supply a name or properties to each memory block?
I thought we did those things via a python client showing all sorts of graphs about memory usage by category (geometry, texture etc) and FPS split into various areas.
all ur base destructors r belong 2 me. there..that solves it.
Quote:
Exactly. The OS is your perfect deallocator.
Maybe he's coding for Amiga.
Quote:
Valgrind? Is that what Linux programmers do instead of having a HTTP server that shows live memory usage sorted by all kinds of criteria while the program is running at normal speed?
The real question is what we Linux guys do in our free-time while you Windows guys hunt down thread synchronization bugs...
valgrind --tool=helgrind anyone?