我没有使用太多指向成员函数的指针,但我认为在使用此类指针时发现了一些危险的情况。
当编译器由于某些优化而决定不为函数分配地址时,就会出现问题。 VS 2015 即使在调试、x86 中也会发生这种情况(禁用优化 - /Od)。我正在重构一个旧系统,将一些代码移动到公共静态库(common.lib)中,以便能够在多个项目中使用。即使不是最好的模式,旧的实现在很大程度上依赖于函数成员指针,我不想改变这一点。例如,我将 ModuleBase 接口添加到一个非常大的旧类中,如下所示:
class ModuleBase
{
public:
typedef void (ModuleBase::*Main)() const; // moved from old module
virtual void FunctionMain() const = 0; // Function has no address, possibly due to compiler optimizations.
virtual void FunctionSecondary() const = 0; // Function has no address, possibly due to compiler optimizations.
};
class OldModule : public ModuleBase
{
public:
virtual void FunctionMain() const {};
virtual void FunctionSecondary() const {};
}
这个想法是将 ModuleBase 移到静态库中,但 OldModule 保留在主 EXE 项目中。虽然 ModuleBase 在主项目中,但它工作得很好,但是当我将它移动到静态 Common.lib 中时,它开始崩溃!我花了大约 2 天的时间才终于注意到,在几个地方,编译器决定(但仅限于静态库)不将地址分配给 ModuleBase 中的 FunctionMain、FunctionSecondary() 等。因此,当指向这些虚拟函数的指针传递给其他例程时,它们为零。
例如在下面的代码中:
new Manager::ModuleDecription(
"Test Module",
"Secondary Scene",
"Description"
PosX,
PosY,
Proc,
&ModuleBase::FunctionSecondary //contains nullptr when in static library!!!!!
结构中的最后一个成员为零,但仅当位于静态库中时才如此。这非常令人讨厌,因为我必须先检查很多其他事情才能注意到这一点。还有其他不为零的指针,因为该结构在构造函数中未归零,因此必须注意地址值不同,并且在尝试调用该函数时会崩溃。
所以我的问题是 -
1)我是否认为这是正确的 - 这是有效的情况(编译器正在删除函数地址,对于在静态库中移动时的相同代码)?
2)如何强制编译器始终保留成员函数地址?