我有一个类,它被广泛用于我软件中的所有代码。此类是具有一些几何函数的点抽象,它由坐标类型模板化,例如 long 或 double。如果这个点在动态库之间传递,我会收到编译器警告 C4252: class 'Point' needs to have dll-interface to be used by clients of class 'OtherClass' 但代码运行良好且快速,因为所有库具有相同的编译设置。
由于我们的政策是完全没有警告,因此我们决定将两个广泛使用的模板特化标记为 dll 导出,如下所示(在带有模板的 header 中):
template class __declspec(dllexport) Point<long>;
template class __declspec(dllexport) Point<double>;
但是现在编译器用普通函数调用替换了所有内联,并且由于这个类被大量使用,我们的代码变得更慢了。
问题是:有没有什么方法可以在使用它的每个库中保持内联调用,但仍然在 dll 之间传递数据并避免警告?
我们使用 Microsoft VC++ 2012 编译器。
最佳答案
根据我的经验,如果速度是个问题,我通过仅使用静态链接代码/ header 实现了更好的性能 inline
和 fastcall
代码而不是 DLL
s,正是出于您所描述的原因,但是,回想起来,我认为可能有某种方法可以实现您所说的,尽管我怀疑基准测试仍会显示静态链接代码更快。
我正在研究强制 DLL
在加载时驻留在内存中(并且确实可以按照文章 here 执行此操作),以便可以实现与内联/静态链接代码类似的性能。
一开始这似乎可行,但是如果 DLL
所在的内存加载在任何时候被分页,它会变得像访问 DLL
一样慢动态编码。
直到我研究了链接到 DLL
的更多方法s 我个人推荐 inline fastcall 代码(如果这是一个选项),尽管这会导致可执行文件变得更大,并且如果内存占用成为问题可能会影响您的发布。
作为您上面提到的两行的快速修复,您可以尝试更改:
template class __declspec(dllexport) Point<long>;
template class __declspec(dllexport) Point<double>;
到
extern template class __declspec(dllexport) Point<long>;
extern template class __declspec(dllexport) Point<double>;
这应该有望解决您遇到的问题。 (有关执行此操作的更多信息可用 here,在该页面上用于导出 STL 类或包含 STL 类的对象的实例,这似乎是同一问题)。
然而,内联(编译阶段“优化”)的原则天生就与从 DLL 导出/导入相对立:前者通过将所有内容组合在一个包中来优化速度,后者通过以下方式优化内存占用/模块化将代码分成不同的较小的包,可以在需要时调用。
注意事项:
fastcall
将一个或多个参数放入寄存器, 从而减少执行所需的内存调用次数。- 对于 MSoft 和 GCC,当您只有 2 个参数时,您可以获得最显着的速度优势。
- Borland 编译器最多允许使用 3 个寄存器/参数
- 另请注意,inline 关键字并不能保证代码会 被内联,这只是一个非常强烈的建议 编译器,但是其他优化标志可以将其删除或内联 您没有标记为内联的其他部分。
希望这对您有所帮助,但一如既往,如果您需要更多信息/帮助,请告诉我。 :)
关于c++ - 如何保持内联调用但避免编译器警告?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21304930/