I have the following class structure for Managing callbacks with different prototypes:
class MethodHandlerBase: public std::enable_shared_from_this<MethodHandlerBase>{
public:
virtual void operator()(void* data) = 0;
virtual ~MethodHandlerBase(){}
};
class MethodHandlerA: public MethodHandlerBase{
private:
MethodHandlerACallback cb;
public:
MethodHandlerA(MethodHandlerACallback cb): cb(cb){}
virtual void operator()(void* data);
};
class MethodHandlerB: public MethodHandlerBase{
private:
MethodHandlerBCallback cb;
public:
MethodHandlerB(MethodHandlerBCallback cb): cb(cb){}
virtual void operator()(void* data);
};
In some cases MethodHandlerA
or MethodHandlerB
might use this
(wrapped in a shared_ptr) in a lambda expression passed to elsewhere, so I need to be sure that it is correctly deleted when needed. Therefore I added the std::enable_shared_from_this<MethodHandlerBase>
inheritance to the base class.
But I read that you usally cannot use std::enable_shared_from_this
via inheritance (apart from using a template, which actually would not really be inheritance anymore). In my understanding this is due to the possible wrongly destruction of the instance. In this case I would assume my code would work properly since it uses a virtual destructor (which is needed anyway).
So am I right with my theory or is there something else going on about std::enable_shared_from_this
inheritance that I did not understand?
EDIT:
To add a short examples of what I plan to use it like:
From inside the class:
void MethodHandlerB::operator()(void* data){
std::shared_ptr<MethodHandlerB> thisPtr = std::dynamic_pointer_cast<MethodHandlerB>(this->shared_from_this());
putLamdaToSomeGlobalEventThing([thisPtr](){
thisPtr->doSomething();
});
}
and from outside
std::vector<MethodHandlerBase> vec{std::make_shared<MethodHandlerB>()};
Some minor points:
void MethodHandlerB::operator()(void* data){
auto thisPtr = std::static_pointer_cast<MethodHandlerB>(this->shared_from_this());
putLamdaToSomeGlobalEventThing([thisPtr = std::move(thisPtr)](){
thisPtr->doSomething();
});
}
this
and the shared pointer, which avoids the cast altogether:void MethodHandlerB::operator()(void* data){
putLamdaToSomeGlobalEventThing([this, thisPtr = shared_from_this()](){
doSomething();
});
}
Edit: as one of the comments points out, if you don't use shared_from_this()
directly on the base class, you're better off just deriving from enable_shared_from_this
in the derived classes. You can do this because C++ supports multiple inheritence.
class MethodHandlerBase {
public:
virtual void operator()(void* data) = 0;
virtual ~MethodHandlerBase(){}
};
class MethodHandlerA:
public MethodHandlerBase,
public std::enable_shared_from_this<MethodHandlerA>
{
private:
MethodHandlerACallback cb;
public:
MethodHandlerA(MethodHandlerACallback cb): cb(cb){}
virtual void operator()(void* data);
};
void MethodHandlerA::operator()(void* data){
putLamdaToSomeGlobalEventThing([self = shared_from_this()](){
self->doSomething();
});
}