睡眠影响std :: thread调用哪个虚拟成员函数?

时间:2018-04-20 09:47:15

标签: c++ multithreading c++11

我不确定这是否是c ++ 11中的预期行为。这是我发现的一个例子。

@+id/imageView_dis1

编译并运行时

#include <iostream>
#include <thread>
using namespace std;

class A {
public:
    virtual void a() = 0;
    thread t;
    A() : t(&A::a, this) {}
    virtual ~A() {
        t.join();
    }
};

class B : public A {
public:
    virtual void a() {
        cout << "B::a" << endl;
    }
};

int main() {
    B b;
    this_thread::sleep_for(chrono::seconds(1));
}

但是当睡眠被移除时......

$ g++ -std=c++11 -pthread test.cpp -o test
$ ./test
B::a
$
发生了一些奇怪的事情

int main() {
    B b;
    //this_thread::sleep_for(chrono::seconds(1));
}

这可能是个错误吗?

2 个答案:

答案 0 :(得分:10)

在构造函数和析构函数virtual函数中的行为方式不同。在A构造函数B尚未初始化,这就是为什么B的虚函数不可能被调用的原因。见virtual

  

当从构造函数或析构函数直接或间接调用虚函数时(包括在构造或销毁类的非静态数据成员期间,例如在成员初始化程序列表中),以及调用的对象apply是正在构造或销毁的对象,被调用的函数是构造函数或析构函数类中的最终覆盖,而不是在更派生的类中覆盖它。换句话说,在构造或破坏期间,不存在更多派生的类。

因此,该成员函数指针&A::a在调用它时在该另一个线程中得到解析。此调用解析使用虚拟表,因为&A::a是指向虚拟成员函数的指针。构造函数所做的第一件事是将虚拟表指针设置为类的虚拟表。如果在B被调用的时间内输入了(this->&A::a)()个构造函数,则会调用B::a。调用(this->&A::a)()的新线程与执行AB构造函数的当前线程之间存在竞争条件。

答案 1 :(得分:1)