2015-11-13 2 views
14

Скажем, я хочу использовать функцию hex(). Я знаю, что он определен в заголовке <ios>, и я также знаю, что он включен в заголовок <iostream>. Разница в том, что в <iostream> гораздо больше функций и других вещей, которые мне не нужны.Есть ли последствия для производительности для включения каждого заголовка?

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

+0

Он будет влиять на размер вашего двоичного файла, но я не думаю, что проблем с производительностью не будет. – Haris

+2

@Haris: нет, это не так, в общем случае. –

+0

@PaulR, будут проблемы с производительностью? – Haris

ответ

24
  • Отсутствие удара по времени выполнения.
  • Однако может быть чрезмерное время компиляции, если включены тонны ненужных заголовков.
  • Также, когда это будет сделано, вы можете создать ненужные перекомпилировать, если, например, заголовок изменен, но файл, который его не использует, включает его.

В небольших проектах (с небольшими заголовками) это не имеет значения. По мере роста проекта, возможно.

+0

Спасибо за редактирование. Красиво сделано. –

+0

Можно добавить некоторые издержки времени выполнения со статической инициализацией переменных в заголовке. – Praxeolitic

+0

Вы правы. Но я думаю, что переменные в заголовках либо сделаны по ошибке, либо редко встречаются в расширенных целях. –

31

Если стандарт говорит, что он определен в заголовке <ios>, тогда включайте заголовок <ios>, потому что вы не можете гарантировать, что он будет включен в любой другой заголовок.

+0

Это замечательный момент, о котором я не думал раньше. –

+0

Это, как правило, неправильно, потому что вы _can_ полагаетесь на некоторые символы, которые должны быть определены, если включен какой-либо другой заголовок; рассмотрим 'std :: begin'. – edmz

+2

Делает ли что-либо в вопросе противоречивым или вопрос, который нужен? – Deduplicator

4

Включение ненужных заголовков имеет следующие недостатки.

  1. Больше времени компиляции, компоновщик должен удалить все неиспользованные символы.
  2. Если вы добавили дополнительные заголовки в CPP, это повлияет только на ваш код.
  3. Но если вы распространяете свой код как библиотеку, и вы добавили ненужные заголовки в свои файлы заголовков. Клиентский код будет обременен поиском заголовков, которые вы использовали.
  4. Не доверяйте косвенному включению, используйте заголовок, в котором действительно определена требуемая функция.
  5. Также в проекте в качестве хорошей практики программирования заголовки должны быть включены в порядке уменьшения зависимости.
//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> 

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

+0

Я бы не стал беспокоиться о точке 5. Очевидно, сначала нужно включить соответствующий заголовочный файл, чтобы убедиться, что нет проблем с зависимостями, но остальные должны просто сортироваться в алфавитном порядке, так как это легко и можно надежно найти какие-либо конкретные один, пусть компилятор (и заголовы) разобратся. – Deduplicator

+2

Компилятор не должен «удалять все неиспользуемые символы» ... компилятор не добавляет эти символы в первую очередь, если функции или объекты фактически не доступны или не определены (не просто объявлены) в код, который он компилирует. – Dmitri

+0

+1 «Не доверяйте косвенному включению». Стефан Т. Лававей («STL») является сторонником реализации STL в Visual Studio. Он явно говорит об этом, потому что есть случаи, когда типы перемещаются в заголовках, и если вы говорите: '#include iostream', зная, что он также включает' istream' для 'std :: cin' и' iostream', включая 'istream' ваш код с перерывом. Всегда включайте заголовки для типов, которые вам нужны, не полагайтесь на косвенность. – Casey

5

TL; DR: В общем, лучше всего включить только то, что вам нужно. В том числе больше может отрицательно сказываться на двоичном размере и запуске (должно быть незначительным), но в основном вредит время компиляции без предварительно скомпилированных заголовков.

Ну, естественно, вы должны включить, по крайней мере, те заголовки, которые гарантированно охватывают все ваши цели.
В любом случае может случиться так, что для стандартных заголовков C++ разрешено включать друг в друга, как того требует разработчик, и заголовкам разрешено включать дополнительные символы в поле std -namespace (см. Why is "using namespace std" considered bad practice?).

Далее, иногда содержащий дополнительный заголовок может привести к созданию дополнительных объектов (см. std::ios_base::Init), хотя хорошо продуманная библиотека минимизирует такие (это единственный экземпляр в стандартной библиотеке, насколько я знаю).

Но большая проблема - это не размер и эффективность скомпилированного (и оптимизированного) двоичного кода (который не должен затрагиваться, кроме предыдущей точки, эффект которой должен быть минимальным), но время компиляции при активном развитии (см. также How does #include <bits/stdc++.h> work in C++?).
И последнее (строго так, что комитет работает над модульным предложением, см. C++ Modules - why were they removed from C++0x? Will they be back later on?), что отрицательно сказалось на добавлении лишних заголовков.

Если вы, естественно, не используете предварительно скомпилированные заголовки (см. Why use Precompiled Headers (C/C++)?), и в этом случае, в том числе больше в предварительно скомпилированных заголовках и, следовательно, везде, а не только там, где это необходимо, до тех пор, пока эти заголовки не будут изменены, фактически уменьшит компиляцию - большую часть времени.

Существует инструмент clang для определения минимальных заголовков, называемый include-what-you-use.
Он анализирует clang AST, чтобы решить, что это как сила, так и слабость:
Вам не нужно учить его обо всех символах, которые заголовок делает доступными, но он также не знает, все ли просто работало таким образом, в этой ревизии или же они являются договорными.
Итак, вам нужно дважды проверить его результаты.

1

Включая ненужные файлы заголовков имеет значение.

  1. Это займет меньше усилий кодирования, чтобы включать в себя вырезать и вставить из обычно необходимых include с. Конечно, более поздняя кодировка теперь обременена тем, что не знает, что действительно нужно.

  2. Специально в C, с ограниченным контролем пространства имен, включая ненужные заголовки, быстро обнаруживает столкновения. Скажем, код определяет глобальную переменную или функцию static, которая соответствовала стандарту, например erfc(), для выполнения некоторой обработки текста. Включив <math.h>, столкновение обнаружено с помощью double erfc(double x), хотя этот файл .c не делает математику FP, но другие файлы .c.

    #include <math.h> 
    char *erfc(char *a, char *b); 
    

Ото, был этот .c файл не входит в <math.h>, во время связи, столкновение было бы обнаружено. Влияние этого задержанного уведомления может быть большим, если кодовая база в течение многих лет не нуждалась в математике FP, и теперь она используется только для обнаружения char *erfc(char *a, char *b), используемого во многих местах.

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

Смежные вопросы