如何在存在VC ++ 2015整个程序优化的情况下正确地公开dll中的接口

时间:2015-11-10 07:55:57

标签: c++ visual-c++ visual-c++-2015

最近我们在遗留代码中遇到了目前从VS2010移植到VS2015的有趣效果。不幸的是,我无法创建一个显示这种效果的小例子,但我会尝试尽可能准确地描述它。

我们有2个dll(我称之为dll A和dll B)。 dll A的项目定义了接口IFoo&派生接口IFxFoo

class __declspec(novtable) IFoo {
public:
    virtual int GetType() = 0;
    virtual ~IFoo() {}
};

class __declspec(novtable) IFxFoo : public IFoo {
public:
    virtual int GetSlot() = 0;
};

在dll B中,使用了两个接口。

class CBImpl : public IFxFoo {
public:
    ...
    void processFoo(IFoo* f) {
        ...
        if (f->GetType() == IFXFOO) {
            IFxFoo* fx = static_cast<IFxFoo>(f); //downcast
            fill(fx);
        }
    }

    void fill(IFxFoo* fx) {
        m_slot = fx->GetSlot();
    }
private:
    int m_slot;
};
将使用不同的IFoo实现调用processFoo()。一些来自dll A,一些来自dll B.

现在发生的事情如下:   - 如果我们在编译dll B时打开整个程序优化,则函数fill()中对虚函数GetSlot()的调用被Visual C ++去虚拟化。这导致我们的程序崩溃。 如果我们要么

,我们可以解决这个问题
  • 整个程序优化的转变
  • 优化填充
  • 或用__declspec(dllimport)/ __declspec(dllexport)标记我们的接口

我现在的问题是:

  • 是我们的假设正确,因为优化器在dll B中只看到IFxFoo的一个实现,并假设这是唯一一个因为IFxFoo没有被标记为来自不同的dll,所以我们的假设是正确的。
  • 什么是创建&#34;接口的最佳方式&#34;在头文件?我们曾经像上面那样做,但这似乎会导致一些问题。
  • 其他编译器(gcc / clang)表现出类似的行为吗?

感谢您的帮助 托拜厄斯

1 个答案:

答案 0 :(得分:0)

使用LTO会导致编译器对任何能够查看完整调用图的函数进行大幅调整。

您所看到的是预期并使用__declspec(dllexport)extern对需要从单独模块使用的函数或明确声明它们作为DLL .def文件的一部分是预期的方式解决问题,因为编译器将不再将函数视为仅内部函数。