我不确定这是否是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));
}
这可能是个错误吗?
答案 0 :(得分:10)
在构造函数和析构函数virtual
函数中的行为方式不同。在A
构造函数B
尚未初始化,这就是为什么B
的虚函数不可能被调用的原因。见virtual
:
当从构造函数或析构函数直接或间接调用虚函数时(包括在构造或销毁类的非静态数据成员期间,例如在成员初始化程序列表中),以及调用的对象apply是正在构造或销毁的对象,被调用的函数是构造函数或析构函数类中的最终覆盖,而不是在更派生的类中覆盖它。换句话说,在构造或破坏期间,不存在更多派生的类。
因此,该成员函数指针&A::a
在调用它时在该另一个线程中得到解析。此调用解析使用虚拟表,因为&A::a
是指向虚拟成员函数的指针。构造函数所做的第一件事是将虚拟表指针设置为类的虚拟表。如果在B
被调用的时间内输入了(this->&A::a)()
个构造函数,则会调用B::a
。调用(this->&A::a)()
的新线程与执行A
和B
构造函数的当前线程之间存在竞争条件。
答案 1 :(得分:1)