2014-12-23 3 views
0

Когда я включаю заголовок hpp-библиотеки boost в двух единицах перевода, выполняется ли компиляция кода форматирования дважды (а двоичный размер вдвое по сравнению с традиционной прекомпилированной библиотекой?)?Каким образом (только наподобие) библиотеки заголовков влияют на размер компиляции?

+0

просто google для "C++ templates code bloat". Ситуация улучшается. – user1095108

+4

Вопрос на самом деле не подлежит ответу: он сильно зависит от компилятора/компоновщика и оптимизируется ли вы для скорости или размера. Вы не должны заканчивать с несколькими определениями в последней программе; но в итоге вы можете использовать более сложные вызовы функций, которые могут (или не могут) увеличить размер программы. –

ответ

3

Вы задали два различных вопроса:

делает код подталкивание компилировать дважды? Да. Чистый эффект заключается в том, что время компиляции, вероятно, немного больше, поскольку компилятор должен переваривать все заголовки для каждого блока компиляции.

бинарный размер двойной? Нет, вероятно, это не так, но это приведет к выбору флажков оптимизации. Шаблон, созданный в блоке A, будет, по сути, иметь один и тот же код реализации, который был создан в блоке B с точно такими же параметрами типа.

Независимо от того, имеет ли он на самом деле один и тот же код, будет зависеть от того, разрешают ли флаги оптимизации встраивание реализации шаблона. Если вы разрешили встраивание, и компилятор решил сделать это, ваш бинарный размер будет увеличиваться по мере того, как компилятор помещает реализацию шаблона в соответствие с вашим кодом, чтобы достичь заявленных целей оптимизации.

Встраивание никогда не возможно с библиотекой только для двоичных объектов, поэтому это одна из причин, по которой ваш двоичный размер может увеличиваться при использовании только для заголовков.

Вот пример, чтобы показать, как НКУ акций шаблон реализации, когда встраивание не включен:

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); 
} 

м .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), даже если он был составлен в совершенно отдельной компиляции единицы.

+0

спасибо! если компилятор может обнаружить, что код дублирует, это потрясающая функция! – user2449761

+0

@ user2449761 lol, шаблоны были с нами на протяжении десятилетий, а не настолько удивительная особенность. – user1095108

+0

@ user2449761 это делается через именование и связь. Все встроенные методы имеют слабую связь, и поскольку имя mangling кодирует все параметры, имена становятся одинаковыми, и только один выбирается компоновщиком. –

2

Есть несколько файлов заголовков форматирования, которые особенно велики (я смотрю на вас boost/lexical_cast.hpp), что приведет к увеличению двоичного файла. Тем не менее, составители предлагают несколько вариантов, чтобы помочь:

MSVC имеет опцию/LTCG (Link времени генерации кода)

GCC имеет -flto (я считаю, включен с -O3)

Эти параметры в целом позволяют компоновщику отбрасывать неиспользуемые компоненты и уменьшать дублирование в блоке компиляции.