C++ 虚函数与boost绑定奇怪行为

C++ 虚函数与boost绑定奇怪行为,c++,boost,C++,Boost,我在Linux下编写的一段代码中看到了一种奇怪的行为,我想与大家分享一下,看看是否有人知道这种行为的原因。 我有一个基类和一个派生类。在基类中我定义了一个虚拟方法,在派生类中我用相同的签名重新定义了该方法。然后我使用boostbind启动了一个线程。下面是一个示例代码: Class Base { public: virtual void DoSomething(); virtual void Init() = 0; ... } Class Derived : publi

我在Linux下编写的一段代码中看到了一种奇怪的行为,我想与大家分享一下,看看是否有人知道这种行为的原因。 我有一个基类和一个派生类。在基类中我定义了一个虚拟方法,在派生类中我用相同的签名重新定义了该方法。然后我使用boostbind启动了一个线程。下面是一个示例代码:

Class Base {
public:
    virtual void DoSomething();
    virtual void Init() = 0;
    ...
}

Class Derived : public Base {
public:
    void DoSomething();
    void Init();
    ...
}
在派生类的Init方法中,我执行了以下操作:

 boost::thread *t = new boost::thread(boost::bind(&Base::DoSomething, this));
基类的DoSomething方法完成了它的本意,而派生类的同一方法是一个空方法,错误地留在了那里。现在,在运行上面的代码时,大多数时候基类的DoSomething都是在线程中执行的,因此应用程序工作正常,但有时不工作。经过一些调试,我注意到了上面的错误,删除派生类的DoSomething解决了这个问题。在调试模式下使用Eclipse时,似乎总是调用派生类的DoSomething方法,而从控制台运行应用程序在大多数情况下都有效,但并不总是有效。这种行为有什么原因吗?我的意思是,为什么bind函数有时使用基类方法,有时使用派生类的相同方法

提前谢谢

编辑以响应@pmr

很难展示一个完整的工作示例,我将尝试展示一些类是如何使用的

首先我实例化一个派生对象,然后在init函数中用上面显示的初始化代码启动线程。DoSomething有一个在向量上迭代的while循环,但我认为这不是重点

void Derived::Init()
{
    ...
    boost::thread *t = new boost::thread(boost::bind(&Base::DoSomething, this));
}

void Base::DoSomething()
{
    while(true) {
        ...
    }
}

void Derived::DoSomething()
{
}

正如您在这段代码中所看到的,派生的DoSomething方法是空的,因此有时我没有看到任何处理,而是在基本DoSomething函数中进行处理。

这里有一个猜测:用于启动线程的对象实际上已被销毁!由于虚拟函数的绑定在销毁过程中会发生变化(当对象被销毁时,所有虚拟函数都会解析,就好像使用的对象是当前被销毁的类的类型一样)。为此,通常将“vtable指针”重置为指向合适的“虚拟函数表”。一旦基地被摧毁,就不需要进一步摧毁该对象


这与您对行为随机性的解释非常吻合:有时父线程的执行速度足够快,可以到达基类构造函数,有时则不能。当使用调试模式编译时,父线程显然在销毁对象之前花费了很长时间。您所说的在许多情况下一切都正常工作也不会真正破坏该映像:通常,有缺陷的代码看起来似乎正常工作,尽管在更仔细地检查时,它实际上显示出不规则的行为。

我想我已经找到了这种行为的原因:首先,我在基类中调用了线程构造函数构造器。我认为这就是问题所在,因为由于基本构造函数是在派生构造函数之前调用的,所以有时候vtable是指向空的派生函数创建的,有时候线程是在vtable创建之前启动的,因此bind函数使用了base方法,这就是它的用途。我猜使用debug会引入一些延迟,因此使用调试器时线程总是绑定到派生类方法,从而导致错误行为。此外,我还尝试将线程创建移动到init函数中,并以这种方式始终调用派生函数。

我们在内部操作系统中面临同样的问题,在构建对象时,我们将一些虚拟函数绑定到另一个工作线程。若操作系统在我们完成派生类的构造函数之前切换到工作线程,则工作线程将使用基类类型调用“this”。因此,我认为我们可以描述它:“this”指针在构造函数和反构造函数中不是线程安全的。

是否提供一个最小的可编译示例?或者至少展示类是如何使用的。嗨,我不认为是这种情况,因为类不会被破坏,我在线程初始化后使用同一类的其他函数(这是某种守护进程,所以应用程序会运行很长时间)。