Virtual destructor

P

persenaama

But it isn't good programming practice in C++.
Your program already knows about types Derived1 and Derived2
so you might as well use them in the calling program.

You're confused. That is a very common pattern in C++ programs and well
accepted, nothing bad or magical is happening.

The whole point is that the program doesn't already "know" about the
types Derived1 and Derived2 in the scope where it only sees Base*, it
only knows the common interface to the base class. If the destructor
isn't virtual, how the correct destructor is called, you propose to
work around this.. how?
 
P

persenaama

You might as well write:
void* p = (void*)(new Derived);
if you are going to conceal the objects actual type.

No, you may not if you prefer to call the (correct) destructor. This
whole thread is about virtual destructors.. you're missing the point by
a country mile.
(I'm not kidding.

I'm not laughing.
Some C programmers actually write "object oriented" code this way.)

Those same people usually store pointer-to-destructor-function in the
"base" struct, too, so that proper cleanup routine can be called.
That's what the "virtual" keyword does in C++ in practise, keeps a
pointer to destructor in memory that is accessible through the
pointer-to-object (very commonly this is called pointer-to-VTBL, each
virtual class has unique VTBL which has pointer to every method of the
class).

We are not talking about simple memory allocation but also code that is
actually being called. The difference is not-so-subtle so it is not
clear why you don't see it as clearly as the rest of us apparently seem
to do.
 
E

E. Robert Tisdale

persenaama said:
We are not talking about simple memory allocation but also code that is
actually being called. The difference is not-so-subtle
so it is not clear why you don't see it as clearly
as the rest of us apparently seem to do.

You have *not* shown us an example
where a virtual destructor is required.

If C++ required a virtual destructor
for every class that had virtual functions,
the compiler would make the destructor virtual automatically.
A virtual destructor call can be very costly if it isn't necessary
so it isn't required.

Marcus Kwok's example shows how a virtual destructor
can be used as an excuse to write bad code.
Bad code is always bad code.
You can't fix it by introducing a virtual destructor.
 
K

Kaz Kylheku

E. Robert Tisdale said:
int main(int argc, char* argv[]) {
Derived* d = new Derived;
delete d;
return 0;
}
g++ -Wall -ansi -pedantic -o main main.cc
./main
B(void)
D(void)
~D(void)
~B(void)

But, of course, allocation from free store was unnecessary.
You should have substituted:

int main(int argc, char* argv[]) {
Derived d;
return 0;
}

On a recent project I worked on, a program failed because it allocated
a large C++ object in automatic storage; but worked when it was
dynamically allocated.

Whether stack space or free store is more precious depends on the
system architecture.
If you find yourself in a situation
where you *must* allocate free storage
(you have not shown us such a case yet),

Such a case happens in embedded systems with small stacks.
 
M

Marcus Kwok

E. Robert Tisdale said:
Marcus Kwok's example shows how a virtual destructor
can be used as an excuse to write bad code.
Bad code is always bad code.
You can't fix it by introducing a virtual destructor.

I also posted the portion of the FAQ that explains the situations where
it is necessary to have a virtual destructor. You have not explained
how using a base class pointer to point to a derived class instance is
"bad".
 
P

persenaama

You have *not* shown us an example
where a virtual destructor is required.

Neither have you, infact, the example you posted was missing the point
and you are using it to argue your case. Some idiots might think that
is brilliant.

But if you insist on seeing example where such construct is required,
download Fusion SDK from www.liimatta.org, you are free to browse the
sourcecode. Take a look for example in the include/core/surface.hpp

I am not going to write a complete application here just to amuse my
vanity, because that is what is required to demonstrate the how the
creation pattern and life-time of the object are both involved in the
discussion. Maybe this is just way over your head?
If C++ required a virtual destructor
for every class that had virtual functions,
the compiler would make the destructor virtual automatically.

You could also write: "If C++ required virtual functions for every
class, the compiler would make the functions virtual automatically.",
and make such as much sense. Would that be a good argument against
virtual methods? No, it wouldn't. Neither is your argument above a good
one against virtual destructors. Let's face it: it is just a method
which is called implicitly when the object is being deleted.

I counter your statement with a question of mine. "If the C++ didn't
require virtual destructor, why the designer of the language and the
standardization comittee included the feature in the language?"

The question is hypothetical, you know the answer already don't you?
Bad code is always bad code.
You can't fix it by introducing a virtual destructor.

Yes, I can see that you are misguided and confused. If there isn't code
you want to call when a polymorphic object is destroyed, you don't need
a virtual destructor. Where you go wrong is that you are yelling
"incompetent" to anyone who does, because it makes you look incompetent
yourself.

Yes, every feature has a price attached. It is a good rule-of-thumb to
follow, however, that when you have a polymorphic class it is a good,
safe and sound practise to make the base class to have a virtual
destructor. The price to pay for code that doesn't suddenly explode on
your face is a small one.

If you aren't a believer of "destructors", don't use'em.
 
P

persenaama

Oh what the hell, here's a complete application where you might want to
see "virtual destructor" being used, the whole usage pattern and
everything:

// begin app source
#include <fusion/core/surface.hpp>
using namespace fusion;

int main()
{
core::init();

// create surface object from a filestream
// (compressed file in this case)
core::surface* picture = core::surface::create("test.zip/test.dds");

// at this point, picture object can be bitmap, cubemap, mipmap..
// since the interface is abstract one, in other words, pure virtual,
// no implementation detail is visible in the surface class..
therefore,
// we must be able to cleanup, free any resources the constructor did
// allocate.. to do this.. we must have a mechanism to call the right
cleanup
// code.. this mechanism is "the virtual destructor", it is typically
invoked like this:
//
// delete picture;
//
// however, in this case we have "resource managed" objects, so we
write
// instead:

picture->release();

// .. but what detail is not relevant to this discussion, because
that is just a simple
// reference counting system, internally it WILL do a call to delete
this; to the
// surface object
}

// end app source

There you go, Tisdale. A complete example of usage pattern where
virtual destructor is useful construct. Knock yourself out.

The header file, I uploaded it here so that you can look at it w/o
downloading the whole kit:

http://www.liimatta.org/misc/surface.hpp

This is called, by-the-way, the "factory design pattern", you might
have heard of it.. maybe just convenient amnesia so that you can play
the "I'm dumb please explain it to me" -game.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,608
Members
45,241
Latest member
Lisa1997

Latest Threads

Top