Advertisement

C++ Destructor problem

Started by July 13, 2000 02:47 PM
7 comments, last by Starfall 24 years, 5 months ago
Howdy I'm running into a bit of trouble with C++ destructors. This is probably a fairly simple thing... but it's irritating me and I've never noticed the problem before. I have two classes, A and B. Each has a constructor and destructor defined. B is inherited from A. I have a pointer to A in my program which is assigned to point to an object of type B. This calls the constructor of B which calls the constructor of A, executes itself, and returns. However, when I destroy the object, because the pointer is of type A, only the destructor of A is run, and not the destructor of B. If I make the pointer of type B, it works fine. I have included a little code snippet so you can see what I am talking about (assume classes A and B are defined):
    

A *aptr = new B();

delete aptr;   // this line does not call B's destructor, only A's

// however...


B *bptr = new B();

delete bptr;   // this line calls B's destructor then A's


    
I'm sure this is something simple, maybe even correct C++, but I'm not 100% on the C++ standard so any advice would be appreciated on how I can make the code call B's destructor. I'm using MSVC 5. Thanks! Starfall Edited by - Starfall on 7/13/00 2:50:56 PM
define A''s destructor as
virtual ~A();

i haven''t tried that with destructors, but i had the similar problem with a method inside my classes and i was told to define it as virtual in the base class, so i did and it worked perfectly. i think it''s the same thing for the destructor too

- Pouya / FOO!!!

#define PURE_STUPIDITY 128 PROGRAMMERS
Advertisement
Aha! So obvious I can''t believe I didn''t think of it! I was somehow under the impression that this should automatically occur for destructors. I use virtual all the time for other member functions, but it never occurred to me...

Thanks for the help.

Starfall
Are you using Visual C++?

I ask, because Visual C++ doesn''t insist on destructors being virtual, whereas I (and others) are certain that the C++ spec requires that a destructor be virtual, whether or not you declare it such.

I''m interested to know if other C++ compilers, such as GCC/DJGPP, Borland, etc, do this.

Anyway, the bottom line is, /always/ declare your destructors to be virtual - not just the base class. Why?

Well, imagine this:

CObject{  virtual ~CObject();};CBaseWindow : public CObject{  ~CBaseWindow();};CButton : public CBaseWindow{  ~CButton();}CObject *pButton = new CButton();delete pButton; 


Can you tell me what would happen? It''s undefined behaviour - I would expect that the CBaseWindow and CObject destructors would get called properly, but not the CButton one, because there''s no polymorphism chain explicitly declared.

This might not be what the C++ spec says, but since when do Microsoft and other obey a spec to the letter?

I think it''s despicable that Visual C++ doesn''t even generate a warning about non-virtual destructors, and that''s at ''warning level 4'' (for those that don''t know, that tells the compiler to be picky as hell).

Personally, I want my compiler to spew errors if it finds a non-virtual destructor, /or/ have an option to give a warning and then treat it as virtual anyway.

Can anyone give a good reason why it should be possible to break the polymorphism chain on destructors?

TheTwistedOne
http://www.angrycake.com
TheTwistedOnehttp://www.angrycake.com
Speed. Virtual gives you dynamic binding -> added overhead. You violate the principles of c++ if you demand that.
A polar bear is a rectangular bear after a coordinate transform.
Since you asked...
Besides speed, there are two other reasons not to make destructors virtual.
1) Size. Adding a single virtual method to a class requires the addition of a pointer to the vtable for each instance of the class. This is usually only 4 bytes, but it would double the size of a small class like this:
class point {    unsigned short x, y;}; 


2) Adding a vtable pointer to a class makes it incompatable with the corresponding struct in C. If you need to pass struct data between libraries in C and C++, you have to make sure that there are no virtual methods (including destructors) on the structs.

However, I agree that the vast majority of time you DO want destructors to be virtual. It would be nice if VC flagged non-virtual destructors as errors, so long as there was a way to #pragma the error off for cases when you KNOW you want non-virtual destructors.
Advertisement
Borland and Metrowerks compilers do not require virtual dtors

Such a requirement, as said before is, in fact, a violation of the C++ spec.

A dtor is virtual if declared as such or, if it inherits from a base class which has a destructor declared as virtual ( just like methods )

If you do not explicitly declare a dtor the compiler generates one for you - if your class inherits from a class with a virtual dtor then the compiler will generate a virtual dtor, otherwise it will create a non-virtual one.

Personally, I like to make sure and declare things virtual in every class in the heirarchy that they need to be. It makes things clearer when looking at one module. For example:


Module A -

class Base
{
public:

Base();
virtual ~Base();

virtual void Nothing() = 0;
};

Module B - ( a separate .cpp file )

- include Module A -

class Derived : public Base
{
private:

long iVal;

public:

Derived();
virtual ~Derived();

virtual void Nothing();
};


However, declaring all methods virtual can be overkill. Especially since virtual causes inline functions to be out-of-line when the compiler cannot determine the type at compilation time.




Edited by - SteveC on July 14, 2000 5:53:51 PM

Edited by - SteveC on July 14, 2000 5:55:13 PM
Armitage: Speed. Hmm. Personally, I''d take predictability over performance in the case of destructors.

Syzygy: Oh. I tend to forget that a struct is a class according to C++. That''s a good reason.

SteveC: I quite agree. Regardless of what a compiler does or doesn''t do, it''s always best to write things out fully, for everybody''s sake.

I''m aware of default constructors and destructors - which is why you''d find a lot of empty ones in my classes, if you were to peek at them.

I''m not talking about functions in general, though. I fully understand that making everything virtual is a road to performance hell.

Overall, I suppose that it''s unfair to demand that the default be that destructors are virtual. The biggest argument against, I think, would be that such is the opposite of the normal behaviour.

I don''t think I''m being unreasonable in desiring compilers to tell you if you forget to make a destructor virtual, though. Even as a turned-off-by-default option.

Are you listening, Bill

TheTwistedOne
http://www.angrycake.com
TheTwistedOnehttp://www.angrycake.com
Well, I misread the question somewhat. I didn't realize that he meant "breaking" a virtual chain. I thought he wanted a reason for omitting a virtual dtor from the beginning (gave my reply in regard to the first post). If you're building a concrete class you shouldn't use virtual, imo, and I honestly don't know what happens if you start making them virtual further down the tree?

But if there is a virtual one at the top, I'd like to find out from the compiler before introducing small...features into my programs


Edited by - Armitage on July 15, 2000 6:07:38 AM

Edited by - Armitage on July 15, 2000 6:09:25 AM
A polar bear is a rectangular bear after a coordinate transform.

This topic is closed to new replies.

Advertisement