假设条件
C ++的仅标头库的优点之一是它们不需要单独编译。
inline
仅当函数在头文件*中定义时,在C和C ++中才有意义。传统上,在C中,使用.c / .h布局,其中标头代表翻译单元的最小公共接口。同样,.cpp / hpp。
题
仅标头库通常比传统布局在代码和执行时间上更有效吗?如果是这样,是否是因为进行了广泛的内联或其他优化?
*-在标头中定义函数使编译器可以在编译任何翻译单元时查看实现,并且实际上使内联代码成为可能
假设条件
C ++的仅标头库的优点之一是它们不需要单独编译。
inline
仅当函数在头文件*中定义时,在C和C ++中才有意义。
传统上,在C中,使用.c / .h布局,其中标头代表翻译单元的最小公共接口。同样,.cpp / hpp。
题
仅标头库通常比传统布局在代码和执行时间上更有效吗?如果是这样,是否是因为进行了广泛的内联或其他优化?
*-在标头中定义函数使编译器可以在编译任何翻译单元时查看实现,并且实际上使内联代码成为可能
Answers:
C ++的仅标头库的优点之一是它们不需要单独编译
不,这不是优势,而恰恰相反-库的主要部分必须在包含时就被编译,而不仅仅是一次。这通常会增加编译时间。但是,如果您指的是Wikipedia此处列出的优点:该文章是有关减少整个构建,打包和部署过程的管理开销的。
在C和C ++中,仅当函数在头文件中定义时,内联才有意义*
这取决于编译器/链接器系统,但是我想对于大多数现有的C和C ++编译器来说都是如此。
传统上,在C中,使用.c / .h布局,其中标头代表翻译单元的最小公共接口。同样,.cpp / hpp。
那基本上是正确的。C ++类头通常不仅仅包含最小的公共接口-它们通常还包含许多私有内容。为了减轻这种情况,使用了PIMPL习惯用法。这类似于仅标头库的“相反”,它试图使必要的标头内容最小化。
但是要回答您的主要问题:这是一个权衡。放入头文件中的库代码越多,编译器就越有机会优化代码以提高速度(如果确实发生这种情况,或者如果增加明显,则是完全不同的问题)。另一方面,头文件中的代码过多会增加编译时间。尤其是在大型C ++项目中,这可能会成为一个严重的问题,请参阅John Lakos撰写的“大型C ++软件设计” -尽管本书有些过时,并且其中描述的某些问题已由现代编译器解决,但总体思路/解决方案仍然有效。
特别是,当您不使用稳定的(第三方)库,而您在项目期间正在开发自己的库时,编译时间就变得很明显。每次在lib中进行更改时,都必须更改头文件,这将导致所有相关单元的重新编译和链接。
恕我直言,仅标头库的流行是由模板元编程的流行引起的。对于大多数编译器,模板库必须是仅标头的,因为编译器仅在提供类型参数时才能启动主编译过程,并且对于完整编译和优化,编译器必须同时“看到两者”-库代码和模板参数值。这样就不可能(或至少很难)为这种库生成任何“预编译”的编译单元。
好吧,让我们首先拆除一些假设:
- C ++的仅标头库的优点之一是它们不需要单独编译。
分开编译意味着如果仅更改一部分,则可能不必重新编译所有内容。
因此,不利而不是优势。
- 在C和C ++中,仅当函数在头文件*中定义时,内联才有意义。
是的,唯一的影响inline
就是one-definition-rule的例外。
但是,如果这些定义在任何方面都不同,那么请告您。
因此,如果函数在编译单元内部,请对其进行标记static
。这也使得内联的可能性更大,因为该功能需要可用才能内联。
尽管如此,还是要看看至少在MSVC ++,gcc和clang支持下的链接时间优化。
- 传统上,在C中,使用.c / .h布局,其中标头代表翻译单元的最小公共接口。同样,.cpp / hpp。
好吧,仅提供最小的接口无疑是实现更高的API和ABI稳定性并最小化编译时间的目标之一。
尤其是C ++类并没有真正适应这一点,因为所有私有位都泄漏到标头中,无论您是否要从其派生,受保护的位都泄漏到标头中。
设计模式PIMPL用于减少此类细节。
但是,在C ++中将接口和实现完全分开的部分是模板。
该委员会试图对导出的模板做一些事情,但是由于过于复杂而无法正常工作,该模板已被放弃。
现在,他们正在开发适当的模块系统,尽管进展缓慢。这将大大减少编译时间,并且还应通过减小其表面来提高API和ABI的稳定性。
仅标头库通常比传统布局在代码和执行时间上更有效吗?如果是这样,是否是因为进行了广泛的内联或其他优化?
仅标头的库可以在代码大小和执行时间上更有效,尽管这取决于该库是否共享,使用了多少库,以何种方式以及内联是否在特定情况下是决定性的胜利。
内联对于优化如此重要的原因不是因为内联本身有很大的提升,而是由于不断传播和进一步优化的机会而打开。