Jochen
Jochen

Reputation: 23

Any way around using a base class that does not have a virtual destructor?

This specific case is for Arduino, but the question applies in general. The SDK provides a Client class, from which other classes (WiFiClient, EthernetClient, and others) derive.

In my own class I have a field of type Client* which can hold any of those derived classes. I'd like to be able to delete clientfield in my class (specifically in its destructor), but because Client does not provide a virtual destructor, that would cause undefined behaviour.

Any suggestions for ways to work around this?

I could Modify Client to add the destructor, but that's not ideal since anyone using my code would have to make that same change on their system.

Upvotes: 0

Views: 104

Answers (3)

j6t
j6t

Reputation: 13387

Can you use shared_ptr? It implements the dynamic dispatch in its deleter. It is important, though, that you allocate the correct shared_ptr type:

shared_ptr<Client> clientfield = make_shared<WifiClient>();

or

shared_ptr<Client> clientfield = shared_ptr<WifiClient>(new <WifiClient>());

This would be wrong:

shared_ptr<Client> clientfield(new <WifiClient>());

To make it correct again, you can pass a suitable deleter:

shared_ptr<Client> clientfield(new <WifiClient>(), default_delete<WifiClient>());

Upvotes: 0

Jarod42
Jarod42

Reputation: 217448

If base class doesn't have virtual destructor, you have to delete it from pointer of it derived type.

Casting is one option:

// No need of `if` as deleting null pointers is noop.
delete dynamic_cast<WifiClient*>(client);
delete dynamic_cast<EthernetClient*>(client);

Better alternative is to use std::shared_ptr which handles the (type-erased) destructor.

std::shared_ptr<Client> client = std::make_shared<WifiClient>(/*..*/);

Note, "refactoring" to std::unique_ptr<Client> (as ownership is not shared for example) would lead to your original issue.

Upvotes: 0

John Zwinck
John Zwinck

Reputation: 249293

All you need to do is cast the pointer to its actual derived type before deleting it, for example:

if (isWifiClient)
    delete static_cast<WifiClient*>(clientfield);
else if (isEthernetClient)
    delete static_cast<EthernetClient*>(clientfield);

Upvotes: 3

Related Questions