By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
446,217 Members | 1,227 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 446,217 IT Pros & Developers. It's quick & easy.

virtual destructor revisted

P: n/a
A reason for declaring a "virtual destructor" for a Base class is to make
sure the destructor of Derived class will be invoked when a pointer of Base
type is used to delete an object of Derived.

Is this the only reason to define "virtual destructor" for a Base class?

Since it's always possible that users of any Base class will delete a
Derived object like that, does this mean that a "virtual destructor" is
always necessary?

Thanks in advance!


Jul 22 '05 #1
Share this Question
Share on Google+
23 Replies


P: n/a
ctick wrote:
A reason for declaring a "virtual destructor" for a Base class is to make
sure the destructor of Derived class will be invoked when a pointer of Base type is used to delete an object of Derived.

Is this the only reason to define "virtual destructor" for a Base class?

Since it's always possible that users of any Base class will delete a
Derived object like that, does this mean that a "virtual destructor" is
always necessary?

Thanks in advance!


Make all destructors virtual unless profiling reveals you really really
really don't need one.

If your class is abstract, with only pure virtual methods, make the
destructor pure virtual too.

Only one sequence of events leads to undefined behavior: A base class has no
virtual destructor, you derive from it, create a 'new' derived object, take
this object's address, convert the address to the base type, and 'delete'.

'delete'ing a base type pointer is not a rare sequence of events in wildly
polymorphic designs. You should take greater care to ensure that the return
value of 'new' is always stored in a smart pointer or equivalent of the
correct derived type, so destruction becomes automatic. And plenty of
polymorphic designs use only the stack to store objects, so all these
situations destroy and clean up correctly.

However, refactors and new features could easily migrate a statically
allocated object into a dynamic one. At this time, nothing in your system
will tell you if your 'delete' creates undefined behavior (except possibly a
lint tool).

The language permits this loophole to permit tuning performance. Sometimes
the tiny overhead of a virtual method table hurts, so you can always take it
out. A keyword called "unvirtual" would be silly, so you must simply always
make destructors virtual.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces
Jul 22 '05 #2

P: n/a

"ctick" <ct***@flare.com> wrote in message
news:bZ*****************@bgtnsc05-news.ops.worldnet.att.net...
A reason for declaring a "virtual destructor" for a Base class is to make
sure the destructor of Derived class will be invoked when a pointer of Base type is used to delete an object of Derived.

Is this the only reason to define "virtual destructor" for a Base class?
Pretty much yes. There is one other rather obscure reason. It might be that
you want class Base to have at least one virtual function (so that you can
use dynamic_cast on it for instance) but you don't have any other suitable
method to declare as virtual.

Since it's always possible that users of any Base class will delete a
Derived object like that, does this mean that a "virtual destructor" is
always necessary?


Not really. There is an overhead to using virtual functions. If your class
is not intended to be used polymorphically then don't use any virtual
functions (including destructor) and document that fact. Unfortunately its
always possible that users will do something stupid.

john
Jul 22 '05 #3

P: n/a
Phlip wrote:
ctick wrote:
A reason for declaring a "virtual destructor" for a Base class
is to make sure the destructor of Derived class will be invoked
when a pointer of Base type is used to delete an object of Derived.

Is this the only reason to define "virtual destructor" for a Base class?

Since it's always possible that users of any Base class
will delete a Derived object like that, does this mean that
a "virtual destructor" is always necessary?


Make all destructors virtual
unless profiling reveals you really really really don't need one.


This is *very* bad advice.
If all C++ destuctors were meant to be virtual,
that feature would have been built into the language --
or the language would have been renamed Java.
Jul 22 '05 #4

P: n/a
John Harrison wrote:
There is an overhead to using virtual functions.
class Base {
public:
virtual
~Base(void) { }
};

class Derived: public Base {
public:
virtual
~Derived(void) { }
};

void blackHole(Base* p) {
delete [] p;
}

Derived* p = new Derived[bzillion];
blackHole(p);

The destructors do nothing and a good C++ compiler
could have optimized them away if they weren't virtual destructors
but, because the destuctor for the base class was declared virtual,
the compiler will be forced to emit code to call the destructor
for Derived a bzillion times -- to do nothing!
If your class is not intended to be used polymorphically,
then don't use any virtual functions (including destructor)
and document that fact.


Even if your class *is* intended to be used polymorphically,
you really need a strong argument to include a virtual destructor.
Jul 22 '05 #5

P: n/a
On Sat, 19 Jun 2004 22:51:01 -0700 in comp.lang.c++, "E. Robert Tisdale"
<E.**************@jpl.nasa.gov> wrote,

This is *very* bad advice.
If all C++ destuctors were meant to be virtual,
that feature would have been built into the language --
or the language would have been renamed Java.


Come on, Robert, you know it's only very ordinary everyday grade bad
advice. Sure it will make your programs slower and eat a bit more
memory for no good reason, but I can't think of a case where it will
make them give wrong answers or undefined behavior. And it might even
save somebody's clueless butt, once in a blue moon. I told you a
million times not to exaggerate.

Jul 22 '05 #6

P: n/a
"David Harmon" <so****@netcom.com.invalid> wrote in message
news:40***************@news.west.earthlink.net

I told you a
million times not to exaggerate.


:) :)
--
John Carson
1. To reply to email address, remove donald
2. Don't reply to email address (post here instead)
Jul 22 '05 #7

P: n/a
ctick posted:
A reason for declaring a "virtual destructor" for a Base class is to
make sure the destructor of Derived class will be invoked when a
pointer of Base type is used to delete an object of Derived.

Is this the only reason to define "virtual destructor" for a Base
class?

Since it's always possible that users of any Base class will delete a
Derived object like that, does this mean that a "virtual destructor" is
always necessary?

Thanks in advance!


Write your program. At the end, analyse it and see if you use a pointer of
type Base* to delete an object of type Derived . If so, declare ~Base
virtual. If not... DON'T! Very simple.
Where things get a little more complex is with reusable code. Let's say you
write a super duper special class:

class SuperDuperSpecial;
You're not guaranteed that the "user" of your class will not...(the
aformentioned).

Solution:

A) Just declare the destructor virtual.

B) Supply two forms:

class SuperDuperSpecialVirtualDestructor;
Jul 22 '05 #8

P: n/a
Phlip wrote in news:ph***************@newssvr33.news.prodigy.com in
comp.lang.c++:
Make all destructors virtual unless profiling reveals you really
really really don't need one.

If your class is abstract, with only pure virtual methods, make the
destructor pure virtual too.
Pointless, the only reason to make a destuctor *pure*-virtual is because
the class has no other pure-virtuals and you want the class to be
abstract.

Only one sequence of events leads to undefined behavior: A base class
has no virtual destructor, you derive from it, create a 'new' derived
object, take this object's address, convert the address to the base
type, and 'delete'.


Nonsense:

- Never use `delete`.
- `new` should only be used to initialize a smart pointer.
- `new` is nessacery in C++, but you shouldn't use it like
you would in a OO / GC language (java/C#).

Just countering your silly advice with silly advice of my own,
sensible people will ignore both of us.

Rob.
--
http://www.victim-prime.dsl.pipex.com/
Jul 22 '05 #9

P: n/a
E. Robert Tisdale wrote:
Phlip wrote:

Make all destructors virtual
unless profiling reveals you really really really don't need one.


This is *very* bad advice.
If all C++ destuctors were meant to be virtual,
that feature would have been built into the language --
or the language would have been renamed Java.


I covered that when I pointed out that a keyword "unvirtual" would be silly.

Read the /Effective C++/ books.

--
Phlip
Jul 22 '05 #10

P: n/a
David Harmon wrote:
E. Robert Tisdale wrote,

This is *very* bad advice.
If all C++ destuctors were meant to be virtual,
that feature would have been built into the language --
or the language would have been renamed Java.


Come on, Robert, you know it's only very ordinary everyday grade bad
advice. Sure it will make your programs slower and eat a bit more
memory for no good reason, but I can't think of a case where it will
make them give wrong answers or undefined behavior. And it might even
save somebody's clueless butt, once in a blue moon. I told you a
million times not to exaggerate.


How much slower?

It's a loaded question. Even figuring out how much slower spends time that
you could have used to take 'new' out of your design, which would make your
destructors early-bound.

Premature optimization is the root of all evil. Not "some" evil.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces
Jul 22 '05 #11

P: n/a
"Phlip" <ph*******@yahoo.com> wrote in message
news:ph***************@newssvr33.news.prodigy.com. ..
If your class is abstract, with only pure virtual methods, make the
destructor pure virtual too.


Why? This advice makes no sense to me.
Jul 22 '05 #12

P: n/a
Andrew Koenig wrote:
Phlip wrote:
If your class is abstract, with only pure virtual methods, make the
destructor pure virtual too.


Why? This advice makes no sense to me.


As someone pointed out, I was trying to remember an alternative advice: To
make a class abstract, if it has no pure virtual methods, make the
destructor pure virtual.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces
Jul 22 '05 #13

P: n/a
> As someone pointed out, I was trying to remember an alternative advice: To
make a class abstract, if it has no pure virtual methods, make the
destructor pure virtual.


If it has no pure virtual methods, why do you want to make it abstract?
Jul 22 '05 #14

P: n/a
Andrew Koenig posted:
As someone pointed out, I was trying to remember an alternative
advice: To make a class abstract, if it has no pure virtual methods,
make the destructor pure virtual.


If it has no pure virtual methods, why do you want to make it abstract?

I asked the exact same question a couple of months ago!

Consider a bank account. The routine for withdrawing cash and lodging cash
is the same for every single type of bank account. So there's going to be
definitions of each function. As such, there'll be no need for any virtual
functions.

There's checking accounts, there's savings accounts, there's student
accounts. But there's no such thing as just "an account". You don't want
people in your bank opening "an account":

Account my_account;
So you declare the destructor as pure virtual. Now some-one can't just open
an account:

Account my_account; //Compile error
They have to open a specific type of account:

SavingsAccount my_account; //Yipee!!
-JKop
Jul 22 '05 #15

P: n/a
* Andrew Koenig:
As someone pointed out, I was trying to remember an alternative advice: To
make a class abstract, if it has no pure virtual methods, make the
destructor pure virtual.


If it has no pure virtual methods, why do you want to make it abstract?


Well, three features of an abstract class are that (1) it can be
inherited from and (2) it cannot be directly instantiated and (3) it
supports polymorphism, especially RTTI, and those three features
coincide precisely with the ideal features of a marker interface.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #16

P: n/a
Alf P. Steinbach wrote:
* Andrew Koenig:
As someone pointed out, I was trying to remember an alternative advice: To make a class abstract, if it has no pure virtual methods, make the
destructor pure virtual.


If it has no pure virtual methods, why do you want to make it abstract?


Well, three features of an abstract class are that (1) it can be
inherited from and (2) it cannot be directly instantiated and (3) it
supports polymorphism, especially RTTI, and those three features
coincide precisely with the ideal features of a marker interface.


Thanks. I was going to say that when I discover the need, I'd have the
technique ready.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces
Jul 22 '05 #17

P: n/a
JKop wrote:
I asked the exact same question a couple of months ago!

Consider a bank account. The routine for withdrawing cash and lodging cash
is the same for every single type of bank account. So there's going to be
definitions of each function. As such, there'll be no need for any virtual
functions.

There's checking accounts, there's savings accounts, there's student
accounts. But there's no such thing as just "an account". You don't want
people in your bank opening "an account":

Account my_account;
So you declare the destructor as pure virtual. Now some-one can't just open an account:

Account my_account; //Compile error
They have to open a specific type of account:

SavingsAccount my_account; //Yipee!!


With any virtual method in that system, it's the Abstract Template Design
Pattern. Without, it's a compilable comment.

Either Savings and Checking are attributes of a concrete Account, or some
Account routine varies its internal features polymorphically. Even then, an
Account could store a reference to an abstract AccountType, which
specializes only the behaviors for Savings and Checking.

Don't inherit without overwhelming need. Prefer delegation where possible.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces
Jul 22 '05 #18

P: n/a
"Alf P. Steinbach" <al***@start.no> wrote...
* Andrew Koenig:
As someone pointed out, I was trying to remember an alternative advice: To make a class abstract, if it has no pure virtual methods, make the
destructor pure virtual.


If it has no pure virtual methods, why do you want to make it abstract?


Well, three features of an abstract class are that (1) it can be
inherited from and (2) it cannot be directly instantiated and (3) it
supports polymorphism, especially RTTI, and those three features
coincide precisely with the ideal features of a marker interface.


Wouldn't it be easier to make its constructor protected instead?
Jul 22 '05 #19

P: n/a
* Victor Bazarov:
"Alf P. Steinbach" <al***@start.no> wrote...
* Andrew Koenig:
> As someone pointed out, I was trying to remember an alternative advice: To > make a class abstract, if it has no pure virtual methods, make the
> destructor pure virtual.

If it has no pure virtual methods, why do you want to make it abstract?


Well, three features of an abstract class are that (1) it can be
inherited from and (2) it cannot be directly instantiated and (3) it
supports polymorphism, especially RTTI, and those three features
coincide precisely with the ideal features of a marker interface.


Wouldn't it be easier to make its constructor protected instead?


Then you lose feature (3).

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #20

P: n/a
* Alf P. Steinbach:
* Victor Bazarov:
"Alf P. Steinbach" <al***@start.no> wrote...
* Andrew Koenig:
> > As someone pointed out, I was trying to remember an alternative

advice: To
> > make a class abstract, if it has no pure virtual methods, make the
> > destructor pure virtual.
>
> If it has no pure virtual methods, why do you want to make it abstract?

Well, three features of an abstract class are that (1) it can be
inherited from and (2) it cannot be directly instantiated and (3) it
supports polymorphism, especially RTTI, and those three features
coincide precisely with the ideal features of a marker interface.


Wouldn't it be easier to make its constructor protected instead?


Then you lose feature (3).


Bang! Bang! He knew that if he ever let wind in the echo chamber, he
would never hear the end of it...

Sorry, you don't lose feature (3), unless the destructor is non-virtual
(which is what I read in addition to what you actually wrote).

Easier, perhaps, but "= 0" conveys the abstractness very directly.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #21

P: n/a
On Sun, 20 Jun 2004 13:00:20 GMT in comp.lang.c++, "Phlip"
<ph*******@yahoo.com> wrote,
How much slower?


An amount that is usually, but not always, insignificant.
Otherwise I would be agreeing with Robert. But it's not really the
speed, it's writing code that you don't need and that complicates your
application. It smells. Don't add "virtual" to anything unless it
serves a _current_ purpose. You aren't going to need it.

Jul 22 '05 #22

P: n/a
David Harmon wrote:
E. Robert Tisdale wrote,
This is *very* bad advice.
If all C++ destuctors were meant to be virtual,
that feature would have been built into the language --
or the language would have been renamed Java.
Come on, Robert,
you know it's only very ordinary everyday grade bad advice.
Sure it will make your programs slower and eat a bit more memory
for no good reason, but I can't think of a case
where it will make them give wrong answers or undefined behavior.
And it might even save somebody's clueless butt,
once in a blue moon.


These are actually very good reasons
for the trade-off that Java (and Smalltalk) make
in sacrificing a little performance and efficiency
to make the language a little simpler and safer.
This is a big win for 90% of all applications
but unacceptable for some high performance applications.
C++ is a little more complicated.
It allows (and requires) the programmer to exercise
more options that can result in code
that is faster and more efficient.
I told you a million times not to exaggerate.

Jul 22 '05 #23

P: n/a
David Harmon wrote:
Phlip wrote,

How much slower?


An amount that is usually, but not always, insignificant.
Otherwise I would be agreeing with Robert. But it's not really the
speed, it's writing code that you don't need and that complicates your
application. It smells. Don't add "virtual" to anything unless it
serves a _current_ purpose. You aren't going to need it.


The Simplicity Principles:

After adding each tiny ability, run this checklist, in order, and refactor
until your code:

0. Obeys your team's Sane Subset and style guidelines
1. Passes All Tests
2. Expresses Intent Clearly
3. Duplicates No Behavior
4. Minimizes Classes, Methods, and Statements.

Repeat those checks, throughout a project's lifecycle, to keep it simple but
understandable at all times. Apply them in order-don't remove that last bit
of duplication if the result wouldn't express intent clearly. Some languages
enable more obfuscation than others do. At least put duplicated things next
to each other.

Doing things your compiler cannot do for you, such as smart pointers,
private unimplemented copy operations, virtual destructors, etc, are at
level 0. You cannot test them into place, or use them to improve expression.
"Design Smells" start at level 2, after the code works.

A team using C++ must maintain awareness of a common Sane Subset. This
includes things like whether colleagues would have provided virtual
destructors, or whether you must go looking for them when you attempt to
polymorph.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces
Jul 22 '05 #24

This discussion thread is closed

Replies have been disabled for this discussion.