我正在尝试实现多态,其中派生类实现了在单独线程中运行的方法:
#include <memory>
#include <thread>
#include <chrono>
class Base
{
public:
std::thread m_jobThread;
~Base() { if (m_jobThread.joinable()) m_jobThread.join(); }
virtual void doJob() = 0;
void doJobInBackground() { m_jobThread = std::thread(&Base::doJob, this); }
};
class Drived : public Base
{
public:
Drived() = default;
virtual void doJob() final { std::this_thread::sleep_for(std::chrono::seconds(1)); }
};
int main(int argc, char const *argv[])
{
Drived d;
d.doJobInBackground();
return 0;
}
如何安全地做到这一点而又不会遇到pure virtual method called
异常?
我希望能够在工作进行时销毁派生对象,并让基类的析构函数处理线程管理。但是由于派生类的vtable在运行基类的析构函数之前已被销毁,所以我得到了一个纯虚方法异常。
我想到了在派生类的析构函数中添加一个stop
方法,以确保线程已连接。但这违反了我的多态设计的目的,我希望派生类仅负责定义doJob
方法,而不是直接或间接处理基类的资源,例如线程... < / p>
有什么可能的想法吗?我需要更改设计吗?
答案 0 :(得分:1)
正如Sam Varshavchik在上面的评论中所指出的,您在此处触发纯虚函数调用的原因是d
的析构函数在第二个线程甚至开始执行之前就已运行。您仅在Base
析构函数中进行同步。但是,到Base
析构函数运行时,对象的Derived
部分已被破坏。此时对象的动态类型仅为Base
,因为这仍然是活动的,因此,虚拟函数调用将分派到基本版本,即纯版本。严格来说,您实际上在这里有未定义的行为,因为在一个线程中销毁该对象而另一个线程可能正在调用该对象的对象违反了[basic.life]/7.2。当析构函数调用开始[basic.life]/1.3时,对象的生命周期结束,第二个线程中的方法调用不inter-thread happen before第一个线程中的析构函数调用……
只是
#include <thread>
#include <chrono>
class Base
{
std::thread m_jobThread;
public:
void join() { if (m_jobThread.joinable()) m_jobThread.join(); }
virtual void doJob() = 0;
void doJobInBackground() { join(); m_jobThread = std::thread(&Base::doJob, this); }
};
class Derived : public Base
{
public:
virtual void doJob() final { std::this_thread::sleep_for(std::chrono::seconds(1)); }
};
int main(int argc, char const* argv[])
{
Derived d;
d.doJobInBackground();
d.join();
return 0;
}
工作正常...