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

Tec*_*gon 8 c++ multithreading c++11

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

#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));
}
Run Code Online (Sandbox Code Playgroud)

编译和运行时

$ g++ -std=c++11 -pthread test.cpp -o test
$ ./test
B::a
$
Run Code Online (Sandbox Code Playgroud)

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

int main() {
    B b;
    //this_thread::sleep_for(chrono::seconds(1));
}
Run Code Online (Sandbox Code Playgroud)

奇怪的事发生了

$ g++ -std=c++11 -pthread test.cpp -o test
$ ./test
pure virtual method called
terminate called without an active exception
Aborted (core dumped)
$
Run Code Online (Sandbox Code Playgroud)

这可能是个错误吗?

Max*_*kin 10

在构造函数和析构virtual函数中的行为方式不同.在As构造函数中B还没有初始化,这就是为什么B不能调用虚函数的原因.见virtual:

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

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