Есть ли последствия для производительности для включения каждого заголовка?
Предположим, что я хочу использовать функцию hex()
. Я знаю, что он определен в заголовке <ios>
, и я также знаю, что он включен в заголовок <iostream>
. Разница в том, что в <iostream>
гораздо больше функций и других вещей, которые мне не нужны.
С точки зрения производительности, я должен заботиться о включении/определении меньших функций, классов и т.д., чем больше?
Ответы
Ответ 1
- Невозможно достичь производительности во время выполнения.
- Однако может быть чрезмерное время компиляции, если включены тонны ненужных заголовков.
- Также, когда это будет сделано, вы можете создать ненужные перекомпиляции, если, например, заголовок изменен, но файл, который его не использует, включает его.
В небольших проектах (включая небольшие заголовки) это не имеет значения. По мере роста проекта он может.
Ответ 2
Если стандарт говорит, что он определен в заголовке <ios>
, тогда включите заголовок <ios>
, потому что вы не можете гарантировать, что он будет включен в/через любой другой заголовок.
Ответ 3
TL; DR: В общем, лучше всего включить только то, что вам нужно. Включение большего количества может отрицательно сказаться на двоичном размере и запуске (должно быть незначительным), но в основном вредит время компиляции без предварительно скомпилированных заголовков.
Ну, естественно, вы должны включить, по крайней мере, те заголовки, которые гарантированно охватывают все ваши приложения.
Иногда может случиться так, что "работать" все равно, потому что стандартным заголовкам С++ разрешено включать друг в друга, как того требует разработчик, и заголовкам разрешено включать дополнительные символы в пространство std
-namespace (см. Почему "using namespace std" считается плохой практикой?.
Далее, иногда включение дополнительного заголовка может привести к созданию дополнительных объектов (см. std::ios_base::Init
), хотя хорошо продуманная библиотека насколько это известно (это единственный экземпляр в стандартной библиотеке, насколько я знаю).
Но большая проблема - это не размер и эффективность скомпилированного (и оптимизированного) двоичного кода (который не должен затрагиваться, кроме предыдущего, эффект которого должен быть минимальным), но время компиляции при активном развитии (см. также Как #include < bits/stdС++. h > работают на С++?).
И последнее (так сильно, что комитет работает над модульным предложением, см. С++ Modules - почему они были удалены из С++ 0x? Вернутся ли они позже??) отрицательно повлияли на добавление лишних заголовков.
Если, конечно, вы не используете предварительно скомпилированные заголовки (см. Зачем использовать Precompiled Headers (C/С++)?), и в этом случае, включая больше в предварительно скомпилированных заголовках и, следовательно, везде, а не только там, где это необходимо, до тех пор, пока эти заголовки не будут изменены, фактически сократит время компиляции большую часть времени.
Существует инструмент clang для определения минимальных заголовков, называемый include-what-you-use.
Он анализирует clang AST, чтобы решить, что это как сила, так и слабость:
Вам не нужно учить его обо всех символах, которые заголовок делает доступными, но он также не знает, все ли в этой редакции было просто разработано, или они являются договорными.
Поэтому вам нужно дважды проверить его результаты.
Ответ 4
Включение ненужных заголовков имеет следующие недостатки.
- Более длительное время компиляции, компоновщик должен удалить все неиспользуемые символы.
- Если вы добавили дополнительные заголовки в CPP, это повлияет только на ваш код.
- Но если вы распространяете свой код как библиотеку, и вы добавили ненужные заголовки в свои файлы заголовков. Клиентский код будет обременен поиском заголовков, которые вы использовали.
- Не доверяйте косвенному включению, используйте заголовок, в котором действительно определенная функция.
- Также в проекте в качестве хорошей практики программирования заголовки должны быть включены в порядке уменьшения зависимости.
//local header -- most dependent on other headers
#include <project/impl.hpp>
//Third party library headers -- moderately dependent on other headers
#include <boost/optional.hpp>
//standard C++ header -- least dependent on other header
#include <string>
И вещи, которые не будут затронуты, - это время выполнения, компоновщик избавится от неиспользуемых символов во время компиляции.
Ответ 5
Включение ненужных файлов заголовков имеет некоторое значение.
-
Требуется меньше усилий по кодированию, чтобы включить вырез и вставку обычно необходимых include
s. Конечно, позднее кодирование теперь обременено незнанием того, что действительно необходимо.
-
Особенно в C с ограниченным управлением пространством имен, включая ненужные заголовки, быстро обнаруживает столкновения. Скажем, код определяет глобальную переменную или функцию static
, которая соответствует стандарту, например erfc()
, для выполнения некоторой обработки текста. Включая <math.h>
, столкновение обнаруживается с помощью double erfc(double x)
, хотя этот файл .c
не выполняет математику FP, а другие файлы .c
делают.
#include <math.h>
char *erfc(char *a, char *b);
OTOH, если этот .c
файл не был включен <math.h>
, во время соединения обнаружение столкновения будет обнаружено. Влияние этого замедленного уведомления может быть большим, если в кодовой базе в течение многих лет не нужна математика FP, а теперь она используется только для обнаружения char *erfc(char *a, char *b)
, используемого во многих местах.
IMO: Приложите разумные усилия, чтобы не включать ненужные файлы заголовков, но не беспокойтесь о включении нескольких дополнительных, особенно если они являются общими. Если существует автоматизированный метод, используйте его для управления включением заголовочного файла.