Visual C++中成员函数指针与前向声明(Forward declaration)导致的异常
问题
demo
考虑下面这样的一段代码:
Foo.h
1 |
|
Foo.cpp
1 |
|
Bar.h
1 |
|
Bar.cpp
1 |
|
main.cpp
1 |
|
问题
上面这段代码在G++与clang等平台均可以正常运行。但是若在msvc中运行,程序会出现异常并退出。 但是如果不使用前向声明(Forward declaration),就不会出现这样的问题。
原因
在其它编译器中,成员函数指针的size是固定的(2个指针长度)
但是在msvc中,成员函数指针的size会根据对应类继承关系的不同而不同。在前向声明中,编译器并不能判断对应类的继承关系,因而会错误地推断成员函数指针的size,并影响后续声明的类的size。进而在不同代码中访问对应内存会导致越界等异常。
这个错误非常隐蔽,即使在调试过程中没有产生异常,也应该修复这个错误
Workaround
对于msvc的项目,如果必须同时使用成员函数指针与前向声明,需要在前向声明语句中加入继承模式关键字来避免潜在的bug, 其中:
Keyword | 适用于 |
---|---|
__single_inheritance | 单继承或无继承关系 |
__multiple_inheritance | 多重继承关系 |
__virtual_inheritance | 虚继承关系 |
例如,对于上面的示例,可以将Foo.h
中的L7的前向声明改为以下行进行修复:
1 | class __single_inheritance Bar; |
这个关键字是Microsoft专用关键字,并不在C++规范内。如果您正在构建跨平台应用,需要使用不同的编译器编译同一份代码,建议通过宏进行区分。
Reference
详细的错误issue请参考:https://developercommunity.visualstudio.com/t/Unexpected-exception-when-using-a-combin/10017095?viewtype=all
Microsoft docs: https://docs.microsoft.com/en-us/cpp/cpp/inheritance-keywords?view=msvc-170
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 EdgeNeko's blog!
评论