virtual function phenomenon

E

Eric

I found the following phenomenon in VC++ 2005:

struct A {};

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

A* p = new B;
delete p; // crashes when executing this line

Does anyone have any insight into why it is crashing there?
 
J

John Harrison

Eric said:
I found the following phenomenon in VC++ 2005:

struct A {};

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

A* p = new B;
delete p; // crashes when executing this line

Does anyone have any insight into why it is crashing there?

Because C++ says that this is undefined behaviour. If you delete a derived
class though a base class pointer then the base class *must* have a virtual
destructor.

Change to this and you will be OK.

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

struct B : public A
{
};

john
 
E

Eric

John Harrison said:
Because C++ says that this is undefined behaviour. If you delete a derived
class though a base class pointer then the base class *must* have a virtual
destructor.

I had thought that what would happen is that the derived class destructor
would not be called but I see you're right about the standard saying the
behavior is undefined. If I make B::~B non-virtual then it runs ok and B::~B
is not called.. However making B::~B virtual causes it to crash.
Is there any simple explanation of this particular implementation mechanism
that causes it to crash when B::~B is made virtual?
 
J

John Harrison

Eric said:
I had thought that what would happen is that the derived class destructor
would not be called but I see you're right about the standard saying the
behavior is undefined. If I make B::~B non-virtual then it runs ok and
B::~B
is not called.. However making B::~B virtual causes it to crash.
Is there any simple explanation of this particular implementation
mechanism
that causes it to crash when B::~B is made virtual?

B contains a vtable, A does not. Therefore the A object embedded in the B
object is offset four bytes from the start of the whole object. Therefore
when you say delete p you are passing a pointer to the deallocation routine
that is different from the pointer that was allocated. At least that seems
to be what is happening on my platform. I bet if you add any virtual
function to A (not a destructor) it will no longer crash. Would still
technically be undefined behaviour of course.

Try this code, with and without the dummy function.

#include <iostream>
using namespace std;

class A
{
//virtual void dummy() {}
};

class B : public A
{
public:
virtual ~B() {}
};

int main()
{
B* b = new B();
A* a = b;
cout << "a = " << a << '\n';
cout << "b = " << b << '\n';
delete a;
}

john
 
E

Eric

John Harrison said:
B contains a vtable, A does not. Therefore the A object embedded in the B
object is offset four bytes from the start of the whole object. Therefore
when you say delete p you are passing a pointer to the deallocation routine
that is different from the pointer that was allocated. At least that seems
to be what is happening on my platform. I bet if you add any virtual
function to A (not a destructor) it will no longer crash. Would still
technically be undefined behaviour of course.

You're correct. I checked and the object layout is as follows:
VPTR < B*
A < A*
B

Adding a virtual function to A causes A to include the VPTR and then both A*
and B* point to the beginning of the object (the VPTR). This would seem to
be a logical implementation.

However, I tried it on the Borland compiler and there was no crashing and
the behavior was as I originally expected it would be.

It seems the Borland object layout with virtual B::~B is:
A < B* and A*
VPTR
B

and the Borland layout with virtual A::~A is:
VPTR < B* and A*
A
B
 

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
474,184
Messages
2,570,973
Members
47,530
Latest member
jameswilliam1

Latest Threads

Top