tags:

views:

190

answers:

6

Do interfaces need a virtual destructor, or is the auto-generated one fine? For example, which of the following two code snippets is best, and why? Please note that these are the WHOLE class. There are no other methods, variables, etc. In Java-speak, this is an "interface".

class Base
{
public:
    virtual void foo() = 0;
    virtual ~Base() {}
};

OR...

class Base
{
public:
    virtual void foo() = 0;
    ~Base() {} // This line can be omitted, but included for clarity.
};

EDIT DUE TO "NOT WHAT I'M LOOKING FOR" ANSWERS:

Exactly what are the consequences of each route. Please don't give vague answers like "it won't be destructed properly". Please tell me exactly what will happen. I'm a bit of an assembly nerd.

Edit 2:

I am well aware that the "virtual" tag means that the destructor won't get called if deleted through a pointer to derived, but (I think) this question ultimately boils down to "is it safe to omit that destructor, for is it truly trivial?"

EDIT 3:

My second edit is just plain wrong and disinformation. Please read the comments by actual smart people for more info.

A: 

No... virtual destructors are not auto generated. You have to declare them explicitely in your base class. But you won't need to declare your destructors virtual for the child classes of Base. This is done by the compiler. The compiler will also make sure that the destructors are called in reversed order of construction (from derived to base).

public class Base 
{
 //...
}

public class Derived
{
   int i = 0;
   //...
}

//...

Base* b = new Derived();

If you didn't have a virtual destructor

delete b;

would cause memory leaks (at least 4 bytes for the integer field), because it would destruct only Base and not Derived. The virtuality makes sure that the derived classes are destroyed, too. You won't have to declare a virtual constructor in Derived, this will be inferred by the compiler, if you declared a virtual destructor in Base.

Simon
+3  A: 

You should use a virtual destructor if you expect people to try to delete objects of a derived class via pointers or references of the parent class. If this is the case, then without a virtual destructor, the derived class will never be properly destructed.

For example,

Derived::~Derived() { // important stuff }
Base *foo = new Derived();
delete foo;

Without a virtual destructor in Base, Derived's destructor will never be called, and important stuff will therefore never happen.

Jordan Lewis
Actually, what happens in this case undefined by C++.
anon
+12  A: 

Consider the following case:

   Base *Var = new Derived();
   delete Var;

You need the virtual destructor, otherwise when you delete Var, the derived class' destructor will never be called.

Justin Ethier
It has no destructor worth mentioning.
Clark Gaebel
@wowus: *Base* has no destructor worth mentioning. You don't know what Derived's destructor does.
Dennis Zickefoose
You're missing the key point here. `Derived::~Derived` isn't getting called unless you declare Base::~Base as virtual.
Peter Kovacs
@wowus - I'm confused, does your derived class have a destructor or not? If so, you should make the `Base` destructor `virtual` by using the top code snippet.
Justin Ethier
I'm pretty sure you have that backwards. Isn't it that when you delete Var, the **Base**'s destructor won't be called; or have I just been doing it wrong my whole life?
Clark Gaebel
Okay, I HAVE been doing it wrong my whole life. Accepted.
Clark Gaebel
No, *you* have it backwards. A lack of a virtual destructor in `Base` means that *only* `Base::~Base` will get called when a pointer of type `Base*` is deleted. If the `Base` destructor *is* virtual, then then derived destructors will get called also.
Tyler McHenry
@bshields, if the pointer is to Derived* then both ~Derived and ~Base will be called, whether the destructors are virtual or not.
Mark Ransom
+1  A: 

In general, a destructor should be either (1) public and virtual, or (2) protected and non-virtual.

Assuming you never expect anyone to delete a class instance via an interface pointer, a protected non-virtual destructor is 100% safe.

If someone tries to delete an interface pointer in case (2), they'll get a compile-time error.

zildjohn01
Did you mean to say a "destructor" in your first sentence?
Justin Ethier
I did. Whoops, nice catch
zildjohn01
+7  A: 

If you delete a derived class object via a base class pointer in C++, the result is undefined behaviour. UB is something you really want to avoid, so you must give base classes a virtual destructor. To quote from the C++ Standard, section 5.3.5:

if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand’s dynamic type and the static type shall have a virtual destructor or the behavior is undefined.

anon
+3  A: 

Replying mostly to the edit:

Nobody can tell you what will happen because the result is "undefined behavior". When you delete a derived class through a pointer to a base that has no virtual destructor, the implementation is free to break down in any number of ways.

Noah Roberts