什么时候只有标题库可以接受?

Rap*_*tor 26 c++ header-files

就个人而言,我非常喜欢仅限标题的库,但有人声称它们会因为过度内联而导致代码膨胀(以及编译时间较长的另一个明显问题).

我在想,这些说法有多少真相(关于臃肿的说法)?

此外,成本是否合理?(显然有一些不可避免的情况,例如它是纯粹或大部分使用模板实现的库,但是我对实际可用的选项更感兴趣.)

我知道就这样的事情而言,没有严格的规则,准则等,但我只是想了解别人对这个问题的看法.

PS是的,这是一个非常模糊和主观的问题,我知道,因此我已将其标记为此类.

Mat*_* M. 7

我为一家拥有自己的"中间件"部门的公司工作,以维护数百个很多团队常用的库.

尽管在同一家公司,我们还避免使用仅限标题的方法,并且因为易于维护而倾向于支持二进制兼容性而不是性能.

普遍的共识是,性能增益(如果有的话)不值得麻烦.

此外,所谓的"代码膨胀"可能对性能产生负面影响,因为要在高速缓存中加载的更多代码意味着更多的高速缓存未命中,并且那些是性能杀手.

在一个理想的世界中,我认为编译器和链接器可能足够智能,不能生成那些"多个定义"规则,但只要不是这样,我会(个人)赞成:

  • 二进制兼容性
  • 非内联(对于超过几行的方法)

你为什么不测试?准备两个库(仅一个标题,另一个不在几行内联方法)并在您的情况下检查它们各自的性能.

编辑:

'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.

使用仅限标头的库,由于您没有库,因此实际上不是二进制兼容的.因此,每次进行一些修复(安全性,严重错误等等)时,您需要提供一个新版本,并且所有依赖于您的库(甚至是间接的)都必须针对这个新版本进行重建!

  • 标题库如何暗示代码膨胀?如果代码意味着更大的代码,编译器通常不会内联.而且,就此而言,二进制兼容性如何受标题库影响? (3认同)

Joe*_*oeG 6

根据我的经验,膨胀不是问题:

  • 仅头文件库使编译器具有更强的内联能力,但它们不会强制编译器内联 - 许多编译器将内联关键字视为忽略多个相同定义的命令.

  • 编译器通常有优化选项来控制内联量;/Os在微软的编译器上.

  • 通常,允许编译器管理速度与大小问题通常会更好.您只能看到实际内联的调用中的膨胀,并且只有在其启发式指示其内联将提高性能时,编译器才会内联它们.

我不会认为代码膨胀是远离标题库的理由 - 但我会敦促你考虑只有标题的方法会增加编译时间.