Say we have a base
class and a derived
. So:
class base {
protected:
~base(){
//...
}
// ...
};
class derived : public base {
// ...
};
And now say that we have this code using the above classes with a smart pointer class:
SmartPointer<base> bptr(new derived());
delete bptr;
I understand that it would prevent slicing of the derived
object by calling the destructor of derived
, but how does it know to do that? Wouldn't the reference stored in the smart pointer be that of type base*
? Does it traverse some kind of hierarchy tree, cast that pointer to derived*
and then call delete? Or is there some other thing that I don't know about?
The implementation is supposedly threadsafe, non-intrusive, and reference counting.
YES, the classes that you see are akin to the ones that I'm testing against. There is apparently a way to do this with THESE GIVEN classes. The main idea as to how is mentioned in my question above, but I'm not sure as to how one such an implementation would work.
First thing is that as it stands the code will not work. The destructor of
base
must be at the very leastprotected
(or derived classes be friends of the base). Aprivate
destructor means that the compiler will not allow you to write the destructor for the derived classes. Now, assuming that you have aprotected
destructor... (Rembember, if you design a class to be extended, provide either a public virtual destructor or a protected non-virtual!)All depends on the implementation of the
SmartPointer
, in particularstd::shared_ptr
(or the boost counterpartboost::shared_ptr
) are able to manage that situation cleanly. The solution performs some sort of partial type erasure of the type for destruction purposes. Basically, the smart pointer has a templated constructor that accepts any pointer that can be assigned to abase
pointer, but because it is templated it knows the concrete type. At that point it stores a syntheticdeleter
function that will call the appropriate destructor.For simplicity, using
std::function
:The code is for exhibition only, it would have to be tweaked for production (where to store the
function
, reference counting...), but it is enough to give you the idea: in the only function where the exact type of the object is known (when creating the smart pointer), you create a wrapper that will call the exact version of the destructor that you need (providing some short of type erasure), then just leave it around and when you need todelete
the object call it instead of thedelete
operator.This can also be used to manage other resources that require calling a special method instead of
delete
:Again there should be quite a lot of work before making this production ready.
Dependency on
std::function
which is used to simplify the erasure, can be eliminated from the problem. In the simple case (only memory allocated withnew
and freed withdelete
is supported in the smart pointer), then just provide adeleter
base class with a single virtualoperator()(void*)
, and then refactor the existingdelete_deleter
into templated derived classes fromdeleter
that overrideoperator()(void*)
with the current implementation. If you need to go for the general case (hold any type of resource) it is not worth the effort, just usestd::function
orboost::function
.