我没有使用太多指向成员函数的指针,但我认为在使用此类指针时发现了一些危险的场景。
当编译器决定不为函数分配地址时,由于某些优化,问题就出现了。它发生在 VS 2015 中,甚至在调试中,x86(禁用优化 -/Od)。我正在重构一个旧系统,将一些代码移动到一个公共(public)静态库 (common.lib) 中,以便能够在多个项目中使用。即使不是最好的模式,旧的实现在很大程度上依赖于函数成员指针,我不想改变它。例如,我将接口(interface) 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) 如何强制编译器始终保留成员函数地址?
最佳答案
抱歉,我发现 Visual Studio 中成员函数指针的地址没有问题。指向基接口(interface)虚函数的指针已经解析好了,即使放在静态库中也是如此。我遇到问题的原因是:
1) 调试器有时会将模板类的函数地址显示为零
2) 崩溃的原因是主项目有/vmg 编译器选项,但我没有把它放在静态库项目中。在这种情况下,应该小心地在所有引用的库项目中始终使用 /vmg(因为这是另一个主题而导致的复杂性)。
无论如何,将指向成员的函数与对象指针一起使用通常是糟糕的底层设计的标志。
我希望这可能对某人有所帮助。
关于c++ - 编译器优化 - 函数没有地址,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54388905/