提问者:小点点

在具有虚拟析构函数的多态继承中使用enable_shared_from_this


我有以下类结构用于管理具有不同原型的回调:

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);
};

在某些情况下,MethodHandleraMethodHandlerb可能在传递到别处的lambda表达式中使用this(包装在shared_ptr),因此我需要确保在需要时正确删除它。 因此,我向基类添加了std::enable_shared_from_this继承。

但是我读到,您通常不能通过继承使用std::enable_shared_from_this(除了使用模板,模板实际上不再是继承)。 在我的理解,这是由于可能错误地破坏实例。 在这种情况下,我假设我的代码可以正常工作,因为它使用了虚拟析构函数(无论如何都需要它)。

那么,我的理论是正确的吗?还是关于std::enable_shared_from_this继承,还有什么我不理解的地方?

编辑:

添加一个简短的例子,说明我打算如何使用它:

从班级内部:

void MethodHandlerB::operator()(void* data){
    std::shared_ptr<MethodHandlerB> thisPtr = std::dynamic_pointer_cast<MethodHandlerB>(this->shared_from_this());
    putLamdaToSomeGlobalEventThing([thisPtr](){
        thisPtr->doSomething();
    });
}

从外面

std::vector<MethodHandlerBase> vec{std::make_shared<MethodHandlerB>()};

共2个答案

匿名用户

一些小问题:

  • 您可以将共享指针移到lambda中以避免原子递增和递减
  • 不需要使用动态指针强制转换,因为您确实知道动态类型(另外您不检查结果不是空的!)
void MethodHandlerB::operator()(void* data){
    auto thisPtr = std::static_pointer_cast<MethodHandlerB>(this->shared_from_this());
    putLamdaToSomeGlobalEventThing([thisPtr = std::move(thisPtr)](){
        thisPtr->doSomething();
    });
}
  • 或者,您可以对this和共享指针使用单独的捕获,这完全避免了强制转换:
void MethodHandlerB::operator()(void* data){
    putLamdaToSomeGlobalEventThing([this, thisPtr = shared_from_this()](){
        doSomething();
    });
}

匿名用户

enable_shared_from_this和shared_ptr调用运算符delete.
如果将基类用于具有虚拟析构函数的类型,运算符delete可以正常工作。