纯虚函数派生类
我有这样的基类:纯虚函数派生类
class Base {
public:
Base();
virtual ~Base();
protected:
virtual on_next_item(std::string& item) = 0;
private:
void read_loop();
};
和此派生类:
class Derived : public Base {
public:
Derived();
virtual ~Derived();
protected:
void on_next_item(std::string& item) override;
};
在Base
类构造我开始一个螺纹,其从套接字读取并调用在派生类上调用的on_next_item()
。 在Base
析构函数中,reader线程通过原子标志停止。 但有时read_loop
仍然叫on_next_item
,我得到一个“纯粹的虚函数调用!”错误。我假设我在竞赛状态下运行:
子类(对象)已经被破坏,因此函数不再被注册。
有没有合适的方法来解决这种竞争条件?
为了完整这里的读者循环:在Base
类的析构
while (running.load())
{
string item = read();
if (running.load())
{
on_text_item(item);
}
}
的行驶标志切换为false。
编辑(完整运行的例子,有被执行多次在这个问题上运行):
#include <atomic>
#include <boost/thread/thread.hpp>
#include <boost/chrono.hpp>
#include <iostream>
class Base
{
public:
Base() : running(true)
{
readerThread = new boost::thread(&Base::read_loop, this);
}
virtual ~Base()
{
running = false;
delete readerThread;
readerThread = nullptr;
}
protected:
virtual void on_next_item(std::string &item) = 0;
private:
boost::thread *readerThread;
void read_loop()
{
std::string element = "Element";
while (running.load())
{
boost::this_thread::sleep_for(boost::chrono::milliseconds(2));
on_next_item(element);
}
}
std::atomic_bool running;
};
class Derived : public Base
{
public:
Derived() : Base()
{
}
virtual ~Derived()
{
}
protected:
virtual void on_next_item(std::string &item)
{
std::cout << "On Next Item " << item << std::endl;
}
};
void constAndDestruct()
{
Derived d;
boost::this_thread::sleep_for(boost::chrono::seconds(2));
}
int main(int argc, char **argv)
{
constAndDestruct();
boost::this_thread::sleep_for(boost::chrono::seconds(2));
}
谢谢!
从构造函数或析构函数调用虚函数是generally considered a bad idea。该函数调用实际上做好像因为此时的Derived
构造尚未被调用的函数不是虚拟的,成员变量或Derived
仍然未初始化...
显而易见的解决方案是将逻辑你的类公共成员函数,并调用该函数只是创建对象后:
Derived d;
d.run();
基本上我不会从析构函数调用虚函数。它是从一个线程上运行的方法调用的。 – Soccertrash
@rodrigo同样适用于对象销毁:'Derived ::〜Derived()'应该调用'Base :: join()'方法来确保调用'on_next_item()'的线程在Derived 'd'的一部分被破坏。 – YSC
@Soccertrash你从一个从构造函数开始的函数调用一个虚拟函数。虚函数可以在Derived构造函数之前或之后调用。这是一场比赛,更糟糕的是。 – rodrigo
我建议以下changes-
-
设置“运行”标记T的值o在〜Derived()而不是〜Base()中是false。 将“运行”的访问级别更改为受保护。
virtual〜Derived() { running = false; }
-
从读者的回路中取出睡眠
而(running.load()){
on_next_item(元件); }
您能照常提供[MCVE]吗?其他任何事情都会导致纯粹的猜测。 – user0042
您可以将逻辑从'Base'的析构函数移动到成员函数。或者这不适合你? –
在构造函数中创建线程似乎不是一个好主意。同样在Base类构造函数中,对象没有完全形成(派生类尚未存在)。 https://*.com/questions/30258639/when-is-it-safe-to-call-this-in-constructor-and-destructor – mksteve