2

I have a question about the following code:

#include <iostream>
#include <boost/scoped_ptr.hpp>

class Interface
{
};

class A : public Interface
{
    public:
        A() { std::cout << "A()" << std::endl; }
        virtual ~A() { std::cout << "~A()" << std::endl; }
};


Interface* get_a()
{
    A* a = new A;
    return a;
}

int main()
{
    {
        std::cout << "1" << std::endl;
        boost::scoped_ptr<Interface> x(get_a());
        std::cout << "2" << std::endl;
    }
    std::cout << "3" << std::endl;
}

It creates the following output:

1
A()
2
3

As you can see, it doesn't call the destructor of A. The only way I see to get the destructor of A being called, is to add a destructor for the Interface class like this:

virtual ~Interface() { }

But I really want to avoid any Implementation in my Interface class and virtual ~Interface() = 0; doesn't work (produces some linker errors complaining about a non existing implementation of ~Interface().

So my question is: What do I have to change in order to make the destructor being called, but (if possible) leave the Interface as an Interface (only abstract methods).

James McNellis
  • 348,265
  • 75
  • 913
  • 977
bb-generation
  • 1,487
  • 12
  • 9
  • This question essentially overlaps with: http://stackoverflow.com/questions/270917/why-should-i-declare-a-virtual-destructor-for-an-abstract-class-in-c – Owen S. Jun 15 '10 at 23:35
  • 2
    You can combine `=0` with an empty body to avoid the error, but there's little benefit in doing so. This is C++, and there is no such thing as an "interface" - it's all just classes - so there's no good reason to avoid functions with bodies. Especially in such an idiomatic case as a virtual destructor. – Pavel Minaev Jun 15 '10 at 23:37
  • I removed the smart pointer tags since this isn't really related about smart pointers, it's about base class destructors. – James McNellis Jun 15 '10 at 23:48

3 Answers3

5

You must define a virtual destructor in the base class, otherwise you'll get no polymorphic behavior.

And more importantly, you get undefined behavior otherwise; §5.3.5/3:

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.

Emphasis mine.


I'd argue the best is this one:

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

inline Interface::~Interface(void) {}

The compiler can easily inline this, unlike a solution where the implementation resides in a source file. (Speaking of which, this solution doesn't even mandate you have one.) It also leaves the class pure virtual.

GManNickG
  • 494,350
  • 52
  • 494
  • 543
  • The other solution (with function outside the body of the class) does not require a source file - you can declare it right there in the header so long as it's `inline`. There is also a very hypothetical possibility that the compiler will completely elide the vtable for a given class if all its functions are pure virtual, including destructor (there is a potentially observable difference due to vtable switching during construction/destruction) - it's normally so marginal that it's not worth the bother, but I worked with a codebase where we actually needed `__novtable` regularly once... – Pavel Minaev Jun 15 '10 at 23:44
  • Thanks! That really seems to be the best solution for this problem :) – bb-generation Jun 15 '10 at 23:48
2

You must declare the destructor virtual if you want to delete derived-class objects via a pointer to your base class interface type, and that destructor must have an implementation.

You may still declare it pure virtual, though:

class Interface
{
public:
    virtual ~Interface() = 0;
};

inline Interface::~Interface() { }
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 3
    You can't do this as written - while pure virtual functions can have bodies, you can't have a function definition and `=0` all in one. You have to put a declaration (with no body) but with `=0` in class body, and the actual definition (with a body) outside, properly qualified. – Pavel Minaev Jun 15 '10 at 23:35
  • 1
    @Pavel: Thanks... I should have learned by now not to use Visual C++ to check syntax :-) – James McNellis Jun 15 '10 at 23:37
  • @James: http://www.comeaucomputing.com/tryitout/ is indispensable for every StackOverflow C++ ninja for precisely this reason :) – Pavel Minaev Jun 15 '10 at 23:41
  • Codepad is great, but uses gcc, which, while generally stricter about standard conformance than VC, is still not quite as pedantic as Comeau (though it's good enough for this particular case). – Pavel Minaev Jun 15 '10 at 23:53
2

You need to define a pure virtual version of the Interface destructor, but you need to also define the body of the destructor. This is a sort of weird case in C++ where even though the function is virtual it must be defined because after the A destructor is called, the Instance destructor will also be called.

Thus the correct answer is:

virtual ~Interface() = 0;

And later, in a cpp file:

Interface::~Interface() {}
SoapBox
  • 20,457
  • 3
  • 51
  • 87