vtable创建/填充时机探究:为何虚函数调用结果不一致?
构造期间虚函数调用与vtable初始化问题
问题现象
运行以下简化代码时,会随机出现两种不同的输出结果:一种是回调调用子类的methodToCall,另一种是调用父类的methodToCall,差异的核心在于线程执行时机与vtable初始化的竞争。
简化代码
#include <iostream> #include <functional> #include <thread> using namespace std; typedef std::function<void (void)> MyCallback; MyCallback clb = NULL; void callCallbackFromThread(void){ while(clb == NULL); clb(); } int someLongTask(void){ volatile unsigned int i = 0; cout << "Start someLongTask" << endl; while(i < 100000000) i++; cout << "End someLongTask" << endl; return i; } class Base{ public: Base(){ clb = std::bind(&Base::_methodToCall, this); cout << "Base-Constructor" << endl; } protected: virtual void methodToCall(void){ cout << "Base methodToCall got called!" << endl; }; private: void _methodToCall(void){ methodToCall(); } }; class Child: public Base{ public: Child() : dummy(someLongTask()){ cout << "Child Constructor" << endl; } protected: void methodToCall(void){ cout << "Child methodToCall got called!" << endl; } private: int dummy; }; int main() { thread t(callCallbackFromThread); Child child; t.join(); clb(); return 0; }
两种输出结果
结果1
Base-Constructor Start someLongTask Child methodToCall got called! End someLongTask Child Constructor Child methodToCall got called!
结果2
Base-ConstructorBase methodToCall got called! Start someLongTask End someLongTask Child Constructor Child methodToCall got called!
原因解析
C++中,类的vtable初始化严格遵循构造顺序:
- 构造
Child对象时,首先执行父类Base的构造函数。此时对象的vtable会被设置为Base的vtable——因为在父类构造期间,对象还不是完整的Child对象,编译器会确保此时调用虚函数只会解析到父类版本。 - 父类构造完成后,才会执行子类的成员初始化(此处是调用
someLongTask)和子类构造函数体。在子类构造逻辑启动前,编译器会将对象的vtable替换为Child的vtable。
两种结果对应两种线程竞争场景:
- 场景1:线程在
someLongTask执行期间调用回调——此时父类构造已完成,子类vtable也已替换完毕,因此methodToCall调用子类版本。 - 场景2:线程在父类构造完成后、子类vtable替换前调用回调——此时对象vtable仍为
Base的,因此methodToCall调用父类版本。
另外,全局变量clb的访问未加同步机制,存在数据竞争,属于C++未定义行为,这是两种结果随机出现的直接诱因。
修复建议
- 避免在构造函数中注册回调或启动线程:构造期间对象尚未完全初始化,极易引发此类问题。
- 添加同步机制:如果必须在构造中处理多线程逻辑,需用互斥量等手段确保对象完全初始化后才允许回调执行。
- 构造完成后再注册回调:比如给
Child类添加init方法,在对象构造完成后手动调用以注册回调,而非在父类构造中完成。
内容的提问来源于stack exchange,提问作者Muperman
相关产品推荐
相关产品推荐

