![]() |
1
7
我为一家有自己的“中间件”部门的公司工作,以维护数百个库,这些库通常由许多团队使用。 尽管我们在同一家公司,但由于易于维护,我们不喜欢只使用头部的方法,更喜欢使用二进制兼容性而不是性能。 一般的共识是,性能提升(如果有的话)不值得麻烦。 此外,所谓的“代码膨胀”可能会对性能产生负面影响,因为更多要加载到缓存中的代码意味着更多的缓存未命中,而这些都是性能杀手。 在一个理想的世界里,我认为编译器和链接器可以足够智能,不生成那些“多重定义”规则,但只要不是这样,我(个人)会赞成:
你为什么不测试?准备这两个库(一个只包含一个头,另一个不包含两行以上的内联方法),并在您的案例中检查它们各自的性能。 编辑: “jalf”(谢谢)指出,我应该精确地定义二进制兼容性的含义。 如果您可以(通常)在不更改自己的库的情况下链接到一个或另一个库,则称给定库的两个版本是二进制兼容的。
因为您只能链接到给定库的一个版本
现在,说我们需要修复
但是,如果不是这样,那么我们将有:
是的,你读得对,即使
对于只包含头的库,由于没有库,因此实际上不兼容二进制。因此,每次进行某些修复(安全性、严重错误等)时,都需要交付新版本,并且所有依赖于您的库(甚至间接地)都必须根据此新版本进行重建! |
![]() |
2
6
根据我的经验,膨胀不是问题:
我不认为代码膨胀是远离只包含头部的库的一个原因——但我希望您考虑一下只包含头部的方法将使编译时间增加多少。 |
![]() |
3
3
我同意,内联库更容易使用。 内联膨胀主要取决于您正在使用的开发平台——特别是编译器/链接器功能。我不认为这是VC9的一个大问题,除了一些角落的案例。 我在一个大型VC6项目的某些地方看到了一些显著的最终尺寸变化,但是很难给出一个特定的“可接受,如果……”。您可能需要在devenv中尝试使用您的代码。 第二个问题可能是编译时,即使使用预编译头(也存在权衡)。 第三,有些构造是有问题的,例如静态数据成员在翻译单元之间共享,或者避免在每个翻译单元中有单独的实例。 我已经看到了以下为用户提供选择的机制:
|
![]() |
4
1
过度内联可能是调用者应该解决的问题,调整他们的编译器选项,而不是被调用者试图通过
我认为,担心链接器无法删除多余的代码副本,更多的原因是担心只从头部库中出现代码膨胀。因此,不管函数实际上是否在调用站点上内联,问题是最终会得到每个使用它的对象文件的函数(或类)的可调用副本。我不记得在C++中不同的翻译单元中对内联函数的地址是否需要比较相等,但即使假设它们是这样做的,因此在链接代码中有一个“规范”的函数副本,也不一定意味着链接器实际上会删除无效的重复函数。如果只在一个翻译单元中定义了函数,那么您可以合理地确信每个使用它的静态库或可执行文件只有一个独立的副本。
我真的不知道这种恐惧有多根深蒂固。我所做的每件事要么是因为内存太紧,以至于我们使用了
在我现在进行的过程中,我认为如果你提供一个只包含标题的库,如果用户不喜欢,他们总是可以处理它。编写一个声明所有函数的新标题和一个包含定义的新翻译单元。类中定义的函数必须移动到外部定义,因此,如果您希望在不要求用户分叉代码的情况下支持这种使用,可以避免这样做并提供两个头:
担心代码膨胀的调用程序可能会在所有文件中包含declare.h,然后编写:
他们可能还需要避免整个程序优化,以确保代码不会被内联,但您不能确保即使是非内联函数也不会被整个程序优化内联。 不担心代码膨胀的调用程序可以在所有文件中使用define.h。 |
![]() |
Gergely Tomcsányi · 内部类和封闭类的单独定义 7 年前 |
![]() |
Qaribullah Khan Yousafzai · 模板类和派生类 7 年前 |
|
Ankur Singh · 类的转发声明:语法错误 7 年前 |
![]() |
Arctic Pi · C-将代码正确地划分为多个文件 7 年前 |
![]() |
Mish · 在另一个类中创建的对象的C++数组 8 年前 |