就个人而言,我非常喜欢仅限标题的库,但有人声称它们会因为过度内联而导致代码膨胀(以及编译时间较长的另一个明显问题).
我在想,这些说法有多少真相(关于臃肿的说法)?
此外,成本是否合理?(显然有一些不可避免的情况,例如它是纯粹或大部分使用模板实现的库,但是我对实际可用的选项更感兴趣.)
我知道就这样的事情而言,没有严格的规则,准则等,但我只是想了解别人对这个问题的看法.
PS是的,这是一个非常模糊和主观的问题,我知道,因此我已将其标记为此类.
我为一家拥有自己的"中间件"部门的公司工作,以维护数百个很多团队常用的库.
尽管在同一家公司,我们还避免使用仅限标题的方法,并且因为易于维护而倾向于支持二进制兼容性而不是性能.
普遍的共识是,性能增益(如果有的话)不值得麻烦.
此外,所谓的"代码膨胀"可能对性能产生负面影响,因为要在高速缓存中加载的更多代码意味着更多的高速缓存未命中,并且那些是性能杀手.
在一个理想的世界中,我认为编译器和链接器可能足够智能,不能生成那些"多个定义"规则,但只要不是这样,我会(个人)赞成:
你为什么不测试?准备两个库(仅一个标题,另一个不在几行内联方法)并在您的情况下检查它们各自的性能.
编辑:
'jalf'(谢谢)已经指出我应该通过二进制兼容性来精确地指出我的意思.
如果您可以(通常)链接到一个或另一个而不更改您自己的库,则给定库的2个版本称为二进制兼容.
因为您只能链接到给定库的一个版本Target
,所以加载的所有库Target
将有效地使用相同的版本......这是此属性的传递性的原因.
MyLib --> Lib1 (v1), Lib2 (v1)
Lib1 (v1) --> Target (v1)
Lib2 (v1) --> Target (v1)
Run Code Online (Sandbox Code Playgroud)
现在,假设我们需要修复Target
仅用于的功能Lib2
,我们提供新版本(v2)
.如果(v2)
是二进制兼容的(v1)
,那么我们可以这样做:
Lib1 (v1) --> Target (v2)
Lib2 (v1) --> Target (v2)
Run Code Online (Sandbox Code Playgroud)
但是,如果情况并非如此,那么我们将:
Lib1 (v2) --> Target (v2)
Lib2 (v2) --> Target (v2)
Run Code Online (Sandbox Code Playgroud)
是的,你没有看错,即使Lib1
没有所需的修复,你的头重建它对抗的新版本Target
,因为该版本是强制性的更新,Lib2
并且Executable
只能针对一个版本进行链接Target
.
使用仅限标头的库,由于您没有库,因此实际上不是二进制兼容的.因此,每次进行一些修复(安全性,严重错误等等)时,您需要提供一个新版本,并且所有依赖于您的库(甚至是间接的)都必须针对这个新版本进行重建!
根据我的经验,膨胀不是问题:
仅头文件库使编译器具有更强的内联能力,但它们不会强制编译器内联 - 许多编译器将内联关键字视为忽略多个相同定义的命令.
编译器通常有优化选项来控制内联量;/Os在微软的编译器上.
通常,允许编译器管理速度与大小问题通常会更好.您只能看到实际内联的调用中的膨胀,并且只有在其启发式指示其内联将提高性能时,编译器才会内联它们.
我不会认为代码膨胀是远离标题库的理由 - 但我会敦促你考虑只有标题的方法会增加编译时间.
归档时间: |
|
查看次数: |
5847 次 |
最近记录: |