Reputation: 2059
There is a virtual class as a callback interface, that I can neither modify, nor ask the author to fix. The only members of the class are a lot of virtual methods that can be overridden, so as to let the library call back into my code. In order to get some callback opportunities, I should make a derived class of that virtual class, and override corresponding virtual methods. If I'm NOT interested in some callback chances, I just need to avoid overriding them.
But, the declaration of that interface class has a defect - its destructor is NOT declared as virtual.
For example:
class callback_t {
public:
virtual void onData( int ) {};
};
I make a child class and do not override the destructor, but when I delete a dynamic object of the class child_t
, I encounter a warning from the compiler (gcc9 with C++17) :
deleting object of polymorphic class type ‘child_t’ which has non-virtual destructor might cause undefined behavior.
class child_t : public callback_t {
public:
~child_t() {
// release things specific to the child...
};
void onData( int ) override {
// do things I want when onData
};
private:
int m_data = 0;
};
int main() {
child_t* pc = new child_t;
// pass pc into the routines of the library
// working...
delete pc; /*deleting object of polymorphic class type ‘child_t’ which has non-virtual destructor might cause undefined behavior */
};
Question: How to correctly and gracefully eliminate the warnning(I must commit codes with no warnning)?
Notes and revising:
I can NOT modify the declaration of class callback_t, I also can NOT ask the author of it to fix! This is a lib that had been released by an authority institution. It's useless to advice me change the base class, and it's no meaning to judge the code quality of the lib;
I never intend to release objects of class child_t with a pointer of the type of the base class, and I known clearly the differenc between virtual-dtor and static-dtor;
The main problem I need to resolve, is to eliminate the compiling warnning, because I'm sure there's no memory leaking, and no omission of restoring some states;
In this case, there's no data, no meaningful codes in the base class, and the only intention of making it, is to be derived from, so it should NOT be marked final. But I tried making the child_t as 'final
', and the warnning went away. I'm not sure this method is correct. If so, I think it is the cheapest methods so far;
I also tried making the dtor of child_t as virtual
, and the warnning went away also. But I am still not sure whether or not it
is correct.
Upvotes: 2
Views: 583
Reputation: 31467
A virtual
destructor is only needed if you need to delete
derived objects via a base class pointer. If you don't need to do that, then the fact that the base class destructor is not virtual
doesn't matter (although it's a fairly big hint that the class was never intended to be inherited from - in modern code it should probably have been marked final
). You can still derive from the class just fine. You just have to be careful about how objects of the derived class are destroyed.
Upvotes: 7
Reputation: 180510
The warning you are getting is a false positive. With
child_t* pc = new child_t;
// pass pc into the routines of the library
// working...
delete pc;
pc
points to a child_t
, and it's static type is pointer to a child_t
, so the correct destructor will be called. If you had
callback_t* pc = new child_t;
// pass pc into the routines of the library
// working...
delete pc;
Then the warning would be correct as only the callback_t
destructor would be called.
There is a work around for this and that is to use a std::shared_ptr
. The pointer stores the correct deleter in it's storage so even if the destructor is not virtual, the correct derived destructor is called instead of the base one. You can see more about this in shared_ptr magic :)
Upvotes: 7