23

为什么 Boost 中的所有库都不是仅标头?换一种说法,是什么使 .lib/.dll 的使用成为强制性的?

是不是当一个类不能是模板或有静态字段时?

4

1 回答 1

31

不同的点,我猜。

  • 二进制大小。仅标头可以给客户端带来大小负担吗?
  • 编译时间。仅标头是否意味着编译性能显着下降?
  • 运行时性能。仅标头可以提供卓越的性能吗?
  • 限制。设计是否只需要标题?

关于二进制大小。

和一点安全感

如果 boost 库中有很多可访问的代码,或者编译器无法争论客户端是否可以访问的代码,则必须将其放入最终的二进制文件中。(*)

在具有包管理(例如基于 RPM 或 .deb)的操作系统上,共享库可能意味着二进制分发大小的大幅减少并具有安全优势:安全修复程序分发速度更快,然后所有 .so/ 自动使用.DLL 用户。所以你有一个重新编译和一个重新分发,但有N个奸商。使用仅包含头文件的库,您有N次重新编译、N次重新分发,总是针对每个修复程序,并且这些N中的某些成员本身已经很大。

(*) 可到达此处表示“可能执行”

关于编译时间。

一些 boost 库非常庞大。如果您愿意#include,每次您在源文件中进行一些更改时,您都必须重新编译您所做的一切#include

这可以用樱桃采摘的标头来对抗,例如

#include <boost/huge-boost-library.hpp> // < BAD
#include <boost/huge-boost-library/just-a-part-of-it.hpp> // < BETTER

但有时你真正需要包含的东西已经大到足以削弱你的重新编译。

对策是使其成为静态或共享库,反过来意味着“完全编译一次(直到下一次 boost 更新)”。

关于运行时性能。

我们还没有到一个全局优化可以解决我们所有的 C++ 性能问题的时代。为确保为编译器提供所需的所有信息,您可以只制作头文件并让编译器做出内联决策。

在这方面,请注意,由于 CPU 上的缓存和推测问题,内联并不总是提供卓越的性能。

另请注意,此论点主要与可能使用得足够频繁的 boost 库有关,例如,人们可能期望boost::shared_ptr<>经常使用,因此是一个相关的性能因素。

但考虑到真正的唯一相关原因boost::shared_ptr<>是只有标题......

关于限制。

C++ 中的一些东西不能放入库中,即模板和枚举。

但请注意,这只是对了一半。您可以为您的真实数据结构和算法编写类型安全的模板化接口,而这些接口又在库中具有它们的运行时通用实现。

同样,应该将C++ 中的一些内容放入源文件中,如果是 boost,则应放入库中。基本上,这就是所有会给出“多重定义”错误的东西,比如static一般的成员变量或全局变量。

在标准库中也可以找到一些示例:在std::cout标准中定义为extern ostream cout;,因此cout基本上需要分发定义一次且仅一次的东西(库或源文件) 。

于 2012-07-06T13:37:12.367 回答