The very well known scenario:
#include <memory>
class A{};
class B : public A {};
int main()
{
std::unique_ptr<A> a = std::make_unique<B>();
// bam, when a gets deleted, we have undefined behavior.
return 0;
}
Moreover, not even Valgrind can catch such an error, provided that the size of A
and B
are the same.
Is there some tool that could catch such errors at least for a debug build, or some idiom which would detect such errors for a specified class?
For gcc you can specify:
-Wdelete-non-virtual-dtor -Wsystem-headers
to see delete-non-virtual-dtor
warning generated by std::default_delete
, it will look as follows:
/usr/local/include/c++/5.3.0/bits/unique_ptr.h:76:2: warning: deleting object of polymorphic class type 'B' which has non-virtual destructor might cause undefined behaviour [-Wdelete-non-virtual-dtor] delete __ptr;
live
btw. your sample classes lack at least one virtual function in base class.
[edit]
to turn it into error use:
-Werror=delete-non-virtual-dtor -Wsystem-headers
It is my strong opinion that one should strictly separate "value-based" classes and "OO-based" classes (for lack of better term).
Value-based classes should have no public bases, and should normally support copy semantics (unless specially designed to disable copying). Objects of such classes have no identities apart from their values. They are interchangeable with their copies.
OO-based classes should have virtual destructors, and should never have copying members publicly accessible. Objects of such classes should only be copied via a virtual clone
method. Such objects have identities separate from their values.
There should be no class with a public base that has a non-virtual destructor or a public copy/move ctor or a public copy/move assignment operator (in the base).
If you maintain this separation, you will have no accidents with object slicing or deletion through a non-polymorphic base pointer.
Unfortunately there are no tools (that I know of) that help maintain this separation. So you need to exercise due diligence while inheriting. It's really simple. Does it have a virtual dtor and inaccessible/deleted copy ctor and copy assignment? You can inherit publicly. No? Avoid potential mess, use composition or private inheritance.
A good class designed for inheritance would have its copying members protected in order to facilitate cloning in descendant classes.
Unfortunately, with third-party classes you don't have a choice, as authors usually leave copying members public, so there's still risk of object slicing. But you will have no risk of improper deletion through a base pointer.
TL;DR no tools, only programmer's due diligence.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With