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

virtual destructor?

P: n/a
Hello,
Can anyone help me with these fairly simple questions.

1) What is the point in virtual destructors - I've heard it's a good thing
for base-classes, but what are the advantages and disadvantages of doing so
/ or not as the case maybe?

2) In the following example, are code sections BD and DD *both* going to get
called? I assume they both always will, but is this guaranteed beyond all
odds in all cases? (When I say is it guaranteed - I mean will they both get
called *at some point*, not necessarily in any particular order)

class B
{
B() {}
virtual ~B() {// code BD //}
};
class D : public B
{
D() {}
virtual ~D() {//code DD//}
};

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


P: n/a
The answer 1 is best illustrated by example:

struct base
{
base() {}
~base() {}
};

class derived
{
int *p;
public:
derived() { p = new int[100]; }
~derived() { delete[] p; }
}

int main()
{
base *b = new derived();
// do some stuff with b
delete b; // oops!
}

Now when b is deleted (the line marked oops), ~base() is called but not
~derived(), so the space pointed to by p in the derived class isn't
deallocated, and you have a memory leak.

If you make the destructor virtual, ~derived() is called as normal.

The only downside I know of to doing this is the overhead of a virtual
function call in general; that is essentially, calling through a double
indirection pointer instead of directly, and the overhead of setting
things up to use virtual functions at all if the destructor is the only
virtual thing. (There is a fair amount of "base overhead" for having
the first virtual function, plus a small cost for each additional one.)

Jul 23 '05 #2

P: n/a
On 2005-03-20, Bonj <a@b.com> wrote:
Hello,
Can anyone help me with these fairly simple questions.

1) What is the point in virtual destructors - I've heard it's a good thing
for base-classes, but what are the advantages and disadvantages of doing so
/ or not as the case maybe?
Any class that you intend to use polymorphically as a base class (any class that
has virtual functions) should have a virtual destructor.
http://www.parashift.com/c++-faq-lit....html#faq-20.7
2) In the following example, are code sections BD and DD *both* going to get
called?
In both of these examples, yes:

void f(){
D x;
// ~D(); ~B();
}

void g() {
B* x = new D;
delete x; // ~D(); ~B();
}
I assume they both always will, but is this guaranteed beyond all
odds in all cases?
In all reasonable examples, excluding obvious memory leaks.
(When I say is it guaranteed - I mean will they both get
called *at some point*, not necessarily in any particular order)


The derived class destructor always gets called first. It's important
that it happens in this order because the derived class destructor may
need to use resources held by the base class object.

Cheers,
--
Donovan Rebbechi
http://pegasus.rutgers.edu/~elflord/
Jul 23 '05 #3

P: n/a
ok, thanks - see inline...

"Evan" <ev****@gmail.com> wrote in message
news:11**********************@g14g2000cwa.googlegr oups.com...
The answer 1 is best illustrated by example:

struct base
{
base() {}
~base() {}
};

class derived //(presuming you meant to put ' class derived : public
base' )
{
int *p;
public:
derived() { p = new int[100]; }
~derived() { delete[] p; }
}

int main()
{
base *b = new derived();
// do some stuff with b
delete b; // oops!
}

Now when b is deleted (the line marked oops), ~base() is called but not
~derived(), so the space pointed to by p in the derived class isn't
deallocated, and you have a memory leak.
ok, so I take it that to make sure *all* destructors of base classes all the
way
up the chain fire, I need to make them virtual (thus answering my second
question aswell...?)

But this raises another question I was pondering on, that I didn't ask:
Let's consider your code amended to have 'virtual ~base()' rather than
just '~base()'. When you do 'delete b', base's destructor fires aswell as
derived's,
because it's virtual. This is what we want. But my other question is - when
you do
'delete b', how does delete know that it's actually deleting an instance of
a 'derived',
rather than an instance of a 'base' - since 'b' is a pointer to a 'base'
(even though it is
actually a derived). What I'm hoping you're going to tell me is that when
'new' runs,
information about the size of the actual type of class instantiated
('derived') is stored
in some hidden memory, in order that delete can be intelligent and delete
the right amount
of memory no matter what kind of pointer it is. Can you just clarify this
for me?

If you make the destructor virtual, ~derived() is called as normal.

The only downside I know of to doing this is the overhead of a virtual
function call in general; that is essentially, calling through a double
indirection pointer instead of directly, and the overhead of setting
things up to use virtual functions at all if the destructor is the only
virtual thing. (There is a fair amount of "base overhead" for having
the first virtual function, plus a small cost for each additional one.)

I'm sure that if this is the worst performance hit this class library
suffers then it'll still be miles faster than mfc. ;-)

Jul 23 '05 #4

P: n/a
ok, cheers.
(Any relation to Toadie, by the way?)

"Donovan Rebbechi" <ab***@aol.com> wrote in message
news:sl******************@panix2.panix.com...
On 2005-03-20, Bonj <a@b.com> wrote:
Hello,
Can anyone help me with these fairly simple questions.

1) What is the point in virtual destructors - I've heard it's a good
thing
for base-classes, but what are the advantages and disadvantages of doing
so
/ or not as the case maybe?


Any class that you intend to use polymorphically as a base class (any
class that
has virtual functions) should have a virtual destructor.
http://www.parashift.com/c++-faq-lit....html#faq-20.7
2) In the following example, are code sections BD and DD *both* going to
get
called?


In both of these examples, yes:

void f(){
D x;
// ~D(); ~B();
}

void g() {
B* x = new D;
delete x; // ~D(); ~B();
}
I assume they both always will, but is this guaranteed beyond all
odds in all cases?


In all reasonable examples, excluding obvious memory leaks.
(When I say is it guaranteed - I mean will they both get
called *at some point*, not necessarily in any particular order)


The derived class destructor always gets called first. It's important
that it happens in this order because the derived class destructor may
need to use resources held by the base class object.

Cheers,
--
Donovan Rebbechi
http://pegasus.rutgers.edu/~elflord/

Jul 23 '05 #5

P: n/a
Evan wrote:
Now when b is deleted (the line marked oops), ~base() is called but not
~derived(), so the space pointed to by p in the derived class isn't
deallocated, and you have a memory leak.


Actually, deleting a derived object by the base class pointer when the
base class destructor is not virtual is UNDEFINED BEHAVIOR.

You can't make any assumptions about what is going to happen.
Jul 23 '05 #6

P: n/a

"Evan" <ev****@gmail.com> wrote in message
news:11**********************@g14g2000cwa.googlegr oups.com...
The answer 1 is best illustrated by example:

struct base
{
base() {}
~base() {}
};

class derived
{
int *p;
public:
derived() { p = new int[100]; }
~derived() { delete[] p; }
}
you meant:

class derived : public base
{
int *p;
public:
derived() : base()
{
p = new int[100];
}
~derived() // should be virtual as explained below
{
delete[] p;
}
};

int main()
{
base *b = new derived();
// do some stuff with b
delete b; // oops!
}

Now when b is deleted (the line marked oops), ~base() is called but not
~derived(), so the space pointed to by p in the derived class isn't
deallocated, and you have a memory leak.

If you make the destructor virtual, ~derived() is called as normal.

The only downside I know of to doing this is the overhead of a virtual
function call in general; that is essentially, calling through a double
indirection pointer instead of directly, and the overhead of setting
things up to use virtual functions at all if the destructor is the only
virtual thing. (There is a fair amount of "base overhead" for having
the first virtual function, plus a small cost for each additional one.)

Jul 23 '05 #7

P: n/a
>ok, so I take it that to make sure *all* destructors of base classes
all the
way
up the chain fire, I need to make them virtual (thus answering my
second
question aswell...?)

Uh... I'm not sure if you have to explicitly mark as virtual the
destructor of a class that is both a subclass and superclass for it to
fire if an object of the most derived class is deleted through a
pointer to the base...
This is what we want. But my other question is - when you do
'delete b', how does delete know that it's actually deleting an instance of a 'derived', rather than an instance of a 'base' - since 'b' is a pointer to a 'base' (even though it is actually a derived). What I'm hoping you're going to tell me is that when 'new' runs, information about the size of the actual type of class instantiated ('derived') is stored in some hidden memory, in order that delete can be intelligent and delete the right amount of memory no matter what kind of pointer it is. Can you just clarify this for me?


The short answer is 'yes'.

The long answer is that somehow new and delete have to work it out
amongst themselves how to do it. There are allocation schemes that
don't require the size to be stored explicitly, but rather computed
from, say, the address of the pointer. The implementation is up to the,
uh, implementor, but if you have a pointer allocated by new, delete has
to be able to figure out the right amount to deallocate.

Jul 23 '05 #8

P: n/a
Uh... I'm not sure if you have to explicitly mark as virtual the
destructor of a class that is both a subclass and superclass for it to
fire if an object of the most derived class is deleted through a
pointer to the base...
What I meant was, if *all* the destructors are virtual, does that mean *all*
the destructors guaranteed to fire?
This is what we want. But my other question is - when you do
'delete b', how does delete know that it's actually deleting an

instance of
a 'derived', rather than an instance of a 'base' - since 'b' is a

pointer to a 'base'
(even though it is actually a derived). What I'm hoping you're going

to tell me is that
when 'new' runs, information about the size of the actual type of

class instantiated
('derived') is stored in some hidden memory, in order that delete can

be intelligent
and delete the right amount of memory no matter what kind of pointer

it is. Can you
just clarify this for me?


The short answer is 'yes'.

The long answer is that somehow new and delete have to work it out
amongst themselves how to do it. There are allocation schemes that
don't require the size to be stored explicitly, but rather computed
from, say, the address of the pointer. The implementation is up to the,
uh, implementor, but if you have a pointer allocated by new, delete has
to be able to figure out the right amount to deallocate.

Jul 23 '05 #9

P: n/a

"Ron Natalie" <ro*@sensor.com> wrote in message
news:42**********************@news.newshosting.com ...
Evan wrote:
Now when b is deleted (the line marked oops), ~base() is called but not
~derived(), so the space pointed to by p in the derived class isn't
deallocated, and you have a memory leak.


Actually, deleting a derived object by the base class pointer when the
base class destructor is not virtual is UNDEFINED BEHAVIOR.

You can't make any assumptions about what is going to happen.

But it's ok when the destructor is virtual, yes?
Jul 23 '05 #10

P: n/a
Bonj wrote:
Uh... I'm not sure if you have to explicitly mark as virtual the
destructor of a class that is both a subclass and superclass for it
to fire if an object of the most derived class is deleted through a
pointer to the base...


What I meant was, if *all* the destructors are virtual, does that
mean *all* the destructors guaranteed to fire?


If the destructor of the class that is the static type that you're deleting
is virtual, then all destructors of the actual object are guaranteed to run
in reverse order of construction.

Example:

struct A
{
~A() {}
};

struct B : A
{
virtual ~B() {}
};

struct C : B
{
~C() {} // implicitly virtual
};

struct D : C
{
~D() {} // implicitly vritual
};
void f()
{
D* pd = new D();

C* pc = pd;
B* pb = pc;
A* pa = pb;

// Of course, in real code, you'd only do 1 of the following
// but for eeposition:

delete pd; // all destructors run
delete pc; // all destructors run
delete pb; // all destructors run
delete pa; // undefined behavior
}

In all the cases where destructors run, they're guranteed to be in the order
D, C, B, A.

Multiple inheritance and virtual inheritance follow the same pattern - as
long as the destructor of the declared type of the pointer you're deleting
is virtual, then all destructors will run in the reverse order of
construction.

You might also see http://www.gotw.ca/gotw/080.htm (and in fact, everything
on the GOTW site).

-cd
Jul 23 '05 #11

P: n/a

This question is simple

"Just remember if this class would be served as base class of other
class, then set deconstructor to virtual is ture"
Jul 23 '05 #12

This discussion thread is closed

Replies have been disabled for this discussion.