当我在两个转换单元中包含boost库hpp头时,boost代码是否会编译两次(并且二进制大小是两倍,与传统的预编译库相比?)?
答案 0 :(得分:3)
你问了两个截然不同的问题:
升级代码编译两次?是的,它确实。最终结果是编译时间可能要长一些,因为编译器必须为每个编译单元消化所有头文件。
二进制大小是双?不,它可能没有,但这将归结为您选择的优化标志。在单元A中实例化的模板将在概念上与在单元B中实例化的实现代码共享相同的实现代码,其中完全相同的类型参数。
它是否实际共享相同的代码将取决于您的优化标志是否允许内联模板实现。如果您已允许内联并且编译器已选择执行此操作,那么随着编译器将模板实现与代码内联,以便实现您所声明的优化目标,您的二进制大小将会增加。
使用仅二进制库永远不可能内联,因此这是使用仅限标头库时二进制大小增加的原因之一。
这是一个示例,说明在未启用内联时gcc如何共享模板实现:
<强> a.cpp 强>
#include <vector>
void test1() {
std::vector<int> myvec;
myvec.push_back(1);
}
<强> b.cpp 强>
#include <vector>
void test2() {
std::vector<int> myvec;
myvec.push_back(1);
}
<强> m.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),即使它被编译成完全独立的编译单元。
答案 1 :(得分:2)
有一些提升头文件特别大(我正在看你boost / lexical_cast.hpp),这会导致二进制文件变大。但是,编译器提供了一些选项来帮助:
MSVC有一个选项/ LTCG(链接时代码生成)
GCC有-flto(我相信是用-O3启用的)
这些选项通常允许链接器丢弃未使用的组件并减少编译单元的重复。