(类似提升)仅标头库如何影响编译大小
How does (boost like) header only libraries influence compilation size?
当我在两个翻译单元中包含提升库 hpp 标头时,提升代码是否编译两次(与传统的预编译库相比,二进制大小翻倍?
你问了两个不同的问题:
提升代码编译两次吗?是的,确实如此。实际效果是编译时间可能会更长一些,因为编译器必须消化每个编译单元的所有标头。
二进制大小是双倍?不,它可能没有,但这将归结为您选择的优化标志。在单元 A 中实例化的模板在名义上将与单元 B 中实例化的模板共享相同的实现代码,具有完全相同的类型参数。
它是否实际共享相同的代码取决于您的优化标志是否允许内联模板实现。如果您允许内联并且编译器已选择这样做,则随着编译器将模板实现与您的代码内联以实现您声明的优化目标,您的二进制大小将增加。
使用仅二进制库永远无法内联,因此这是使用仅标头库时二进制大小可能会增长的原因之一。
以下示例显示了 gcc 在未启用内联时如何共享模板实现:
答.cpp
#include <vector>
void test1() {
std::vector<int> myvec;
myvec.push_back(1);
}
乙.cpp
#include <vector>
void test2() {
std::vector<int> myvec;
myvec.push_back(1);
}
米.cpp
extern void test1(),test2();
main() {
test1();
test2();
}
汇编
g++ -g -O0 -fno-inline -c m.cpp
g++ -g -O0 -fno-inline -c a.cpp
g++ -g -O0 -fno-inline -c b.cpp
g++ -o a.out a.o b.o m.o
objdump -S a.out |less
Objdump 的分析
void test1() {
// [snip]
myvec.push_back(1);
// [snip]
4008a0: e8 d1 00 00 00 callq 400976 <_ZNSt6vectorIiSaIiEE9push_backERKi>
void test2() {
// [snip]
myvec.push_back(1);
// [snip]
401548: e8 29 f4 ff ff callq 400976 <_ZNSt6vectorIiSaIiEE9push_backERKi>
请注意如何使用相同的 push_back
实现(位置 400976(,即使它被编译为完全独立的编译单元。
有一些 boost
头文件特别大(我在看你 boost/lexical_cast.hpp(,这将导致二进制文件更大。但是,编译器提供了一些选项来提供帮助:
MSVC 有一个选项/LTCG(链接时代码生成(
GCC 有 -flto(我相信是用 -O3 启用的(
这些选项通常允许链接器丢弃未使用的组件,并减少整个编译单元中的重复。
相关文章:
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- 为什么擦除方法会影响结束方法
- 内联如何影响模块接口中的成员函数
- 为什么返回类型的'const'限定符对标有 __forceinline/内联的函数没有影响?
- 在容量内调整矢量大小时的性能影响
- 重载运算符的范围是什么?它是否会影响作为类成员的集合的插入函数?
- 未达到的情况会影响开关外壳性能
- 循环仅对第一行正常工作.其他行不受 for 的影响
- 处理影响跨不同线程共享对象的定时回调的最佳方法是什么?
- 模板如何影响C++中隐式声明的规则?
- 命名空间信息会影响C++的可读性
- [[可能]]和[[不太可能]]影响程序汇编的简单示例?
- 如何保护非托管应用程序中的字符串不受进程转储的影响
- 检查nullptr是否100%保护内存布局不受segfault影响
- 为什么 std::set.erase(first, last) 会影响从中获取 (first, last) 的容器?
- 发布代码的 gdb 堆栈跟踪可读性如何影响 x64?
- "virtual"对C++析构函数有何影响?
- 如果我对"while"块发表评论,为什么程序会死机?其中的"yield"线有何影响?
- Qt也不例外.这对C++代码有何影响
- 基例如何影响使用递归函数的哪些行