GNU compiler warning "class has virtual functions but non-virtual destructor"

C++Gcc

C++ Problem Overview


I have defined an interface in C++, i.e. a class containing only pure virtual functions.

I want to explicitly forbid users of the interface to delete the object through a pointer to the interface, so I declared a protected and non-virtual destructor for the interface, something like:

class ITest{
public:
    virtual void doSomething() = 0;

protected:
    ~ITest(){}
};

void someFunction(ITest * test){
    test->doSomething(); // ok
    // deleting object is not allowed
    // delete test; 
}

The GNU compiler gives me a warning saying:

> class 'ITest' has virtual functions but non-virtual destructor

Once the destructor is protected, what is the difference in having it virtual or non-virtual?

Do you think this warning can be safely ignored or silenced?

C++ Solutions


Solution 1 - C++

It's more or less a bug in the compiler. Note that in more recent versions of the compiler this warning does not get thrown (at least in 4.3 it doesn't). Having the destructor be protected and non-virtual is completely legitimate in your case.

See here for an excellent article by Herb Sutter on the subject. From the article:

Guideline #4: A base class destructor should be either public and virtual, or protected and nonvirtual.

Solution 2 - C++

Some of the comments on this answer relate to an earlier answer I gave, which was wrong.

A protected destructor means that it can only be called from a base class, not through delete. That means that an ITest* cannot be directly deleted, only a derived class can. The derived class may well want a virtual destructor. There is nothing wrong with your code at all.

However, since you cannot locally disable a warning in GCC, and you already have a vtable, you could consider just making the destructor virtual anyway. It will cost you 4 bytes for the program (not per class instance), maximum. Since you might have given your derived class a virtual dtor, you may find that it costs you nothing.

Solution 3 - C++

If you insist on doing this, go ahead and pass -Wno-non-virtual-dtor to GCC. This warning doesn't seem to be turned on by default, so you must have enabled it with -Wall or -Weffc++. However, I think it's a useful warning, because in most situations this would be a bug.

Solution 4 - C++

It's an interface class, so it's reasonable you should not delete objects implementing that interface via that interface. A common case of that is an interface for objects created by a factory which should be returned to the factory. (Having objects contain a pointer to their factory might be quite expensive).

I'd agree with the observation that GCC is whining. Instead, it should simply warn when you delete an ITest*. That's where the real danger lies.

Solution 5 - C++

My personal view is that you'd doing the correct thing and the compiler is broken. I'd disable the warning (locally in the file which defines the interface) if possible,

I find that I use this pattern (small 'p') quite a lot. In fact I find that it's more common for my interfaces to have protected dtors than it is for them to have public ones. However I don't think it's actually that common an idiom (it doesn't get spoken about that much) and I guess back when the warning was added to GCC it was appropriate to try and enforce the older 'dtor must be virtual if you have virtual functions' rule. Personally I updated that rule to 'dtor must be virtual if you have virtual functions and wish users to be able to delete instances of the interface through the interface else the dtor should be protected and non virtual' ages ago ;)

Solution 6 - C++

If the destructor is virtual it makes sure that the base class destructor is also called fore doing the cleanup, otherwise some leaks can result from that code. So you should make sure that the program has no such warnings (prefferably no warnings at all).

Solution 7 - C++

If you had code in one of ITest's methods that tried to delete itself (a bad idea, but legal), the derived class's destructor wouldn't be called. You should still make your destructor virtual, even if you never intend to delete a derived instance via a base-class pointer.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPaolo TedescoView Question on Stackoverflow
Solution 1 - C++Greg RogersView Answer on Stackoverflow
Solution 2 - C++Airsource LtdView Answer on Stackoverflow
Solution 3 - C++bk1eView Answer on Stackoverflow
Solution 4 - C++MSaltersView Answer on Stackoverflow
Solution 5 - C++Len HolgateView Answer on Stackoverflow
Solution 6 - C++INSView Answer on Stackoverflow
Solution 7 - C++Adam RosenfieldView Answer on Stackoverflow