标头库的好处

时间:2012-10-01 10:15:39

标签: c++ header-only

仅限标题库有什么好处,为什么要编写它以反对将实现放入单独的文件?

5 个答案:

答案 0 :(得分:51)

仅限标题库的好处:

  • 简化构建过程。您不需要构建库,也不需要在构建的链接步骤中指定已编译的库。如果你有一个编译库,你可能想要构建它的多个版本:一个编译启用调试,另一个启用优化,可能还有另一个符号删除。对于多平台系统而言甚至可能更多。

仅限标题库的缺点:

  • 更大的目标文件。来自某个源文件中使用的库的每个内联方法也将在该源文件的编译对象文件中获得一个弱符号,即行外定义。这会降低编译器的速度并降低链接器的速度。编译器必须生成所有膨胀,然后链接器必须将其过滤掉。

  • 更长时间的编译。除了上面提到的膨胀问题之外,编译将花费更长的时间,因为标题本身比仅使用标题库而不是编译库更大。对于使用该库的每个源文件,需要解析那些大标题。另一个因素是,只有头文件库中的头文件必须具有内联定义所需的#include头文件以及将库构建为编译库时所需的头文件。

    < / LI>
  • 更纠结的编译。由于只有标头库需要额外的#include,因此您只能使用仅限标头的库获得更多依赖关系。更改库中某些键函数的实现,您可能需要重新编译整个项目。在编译库的源文件中进行更改,您只需重新编译一个库源文件,使用新的.o文件更新已编译的库,然后重新链接应用程序。

  • 让人难以阅读。即使有最好的文档,库的用户也经常不得不求助于阅读库的标题。标题库中的标题填充了实现细节,这些细节会妨碍理解界面。使用已编译的库,您所看到的只是界面和对实现操作的简要评论,而这通常是您想要的。这真的是你应该想要的。您不必了解实现细节以了解如何使用该库。

答案 1 :(得分:47)

在某些情况下,只有标题库是唯一的选项,例如处理模板时。

拥有仅限标头的库也意味着您不必担心可能使用库的不同平台。分离实现时,通常会隐藏实现详细信息,并将库作为标头和库(libdll.so文件)的组合进行分发。当然,这些必须针对您提供支持的所有不同操作系统/版本进行编译。

您也可以分发实施文件,但这对用户来说意味着额外的步骤 - 在使用之前编译您的库。

当然,这适用于逐个案例。例如,仅标头库有时会增加代码大小&amp; 编译时间。

答案 2 :(得分:11)

我知道这是一个旧线程,但没有人提到过ABI接口或特定的编译器问题。所以我想我会的。

这基本上是基于这样一个概念:你要么编写一个带有标题的库来分发给人们,要么重用自己而不是把所有东西放在标题中。如果您正在考虑重用标题和源文件并在每个项目中重新编译这些文件,那么这并不适用。

基本上,如果您编译C ++代码并使用一个编译器构建库,那么用户会尝试将该库与不同的编译器或同一编译器的不同版本一起使用,那么由于二进制文件,您可能会遇到链接器错误或奇怪的运行时行为不相容性。

例如,编译器供应商经常在版本之间更改STL的实现。如果你在一个接受std :: vector的库中有一个函数,那么它希望该类中的字节按照它们在编译库时的排列方式排列。如果在新的编译器版本中,供应商已经对std :: vector进行了效率改进,那么用户的代码会看到可能具有不同结构的新类,并将该新结构传递到库中。一切都从那里走下坡路......这就是为什么建议不要跨越库边界传递STL对象。这同样适用于C运行时(CRT)类型。

在谈论CRT时,您的库和用户的源代码通常需要链接到同一个CRT。使用Visual Studio,如果使用多线程CRT构建库,但是用户链接到多线程调试CRT,那么您将遇到链接问题,因为您的库可能找不到它需要的符号。我不记得它是哪个功能,但对于Visual Studio 2015,Microsoft内联一个CRT功能。突然它在标题中而不是CRT库中,因此期望在链接时找到它的库不再能够做到并且这会产生链接错误。结果是这些库需要使用Visual Studio 2015重新编译。

如果您使用Windows API但是使用不同的Unicode设置为库用户构建,也可能会出现链接错误或奇怪的行为。这是因为Windows API具有使用Unicode或ASCII字符串和宏/定义的函数,这些函数根据项目的Unicode设置自动使用正确的类型。如果您跨越错误类型的库边界传递一个字符串,那么事情就会在运行时中断。或者您可能会发现程序首先没有链接。

对于从其他第三方库(例如,特征向量或GSL矩阵)跨库边界传递对象/类型,这些也是如此。如果第三方库在您编译库和用户编译代码之间更改了标题,那么事情就会中断。

基本上为了安全起见,您可以跨库边界传递的唯一内容是内置类型和普通旧数据(POD)。理想情况下,任何POD都应该在您自己的标头中定义的结构中,并且不依赖于任何第三方标头。

如果你提供一个只有头文件库,那么所有代码​​都会使用相同的编译器设置和相同的头文件进行编译,因此很多这些问题都会消失(提供你和你的用户使用的第三部分库的版本是API兼容的)。

然而,上面已经提到了负面因素,例如编译时间增加。此外,您可能正在经营一家公司,因此您可能不希望将所有源代码实施细节交给所有用户,以防其中一个用户窃取它。

答案 3 :(得分:8)

主要的“好处”是它要求你提供源代码,所以 你最终会得到关于机器和编译器的错误报告 从来没有听说过。当库完全是模板时,你没有 很多选择,但是当你有选择时,标题通常都很差 工程选择。 (另一方面,当然,标题仅表示 您不必记录任何集成过程。)

答案 4 :(得分:0)

可以通过链接时间优化(LTO)进行内联

我想强调这一点,因为它降低了仅标头库的两个主要优点之一的值:“您需要在标头上进行内联定义”。

Link-time optimization and inline

上显示了一个最小的具体示例。

因此,您只需传递一个标志,就可以在目标文件中进行内联而不需要任何重构工作,而无需再为此保留标题中的定义。

LTO也可能有其缺点:Is there a reason why not to use link-time optimization (LTO)?