Многократное включение заголовочных файлов приводит к увеличению времени компиляции? - PullRequest
4 голосов
/ 19 августа 2011

Увеличивает ли количество включенных одних и тех же заголовочных файлов время компиляции?

Например, предположим, что каждый файл в моем проекте использует <iostream> <string> <vector> и <algorithm>.И если я включу много файлов в свой исходный код, то увеличит ли это время компиляции?

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

На самом деле, кто-то из моих знакомых предложил несколько идей для удаления таких множественных включений.Тем не менее, я считаю, что они полностью противоречат передовым методам проектирования в c ++.Но все еще было интересно, что может быть причиной того, что он предложил эти изменения?

Ответы [ 8 ]

11 голосов
/ 19 августа 2011

Большинство из этих ответов неверны ... Для современных компиляторов есть издержки ноль для многократного включения одного и того же файла, при условии, что заголовок использует обычную идиому "include guard".

Например, препроцессор GCC имеет специальный код для распознавания включенной идиомы защиты .Он даже не откроет файл заголовка (не говоря уже о прочтении) для второй и последующих директив #include.

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

1 голос
/ 19 августа 2011

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

1 голос
/ 19 августа 2011

Каждый раз, когда #include <something.h> встречается в вашем исходном файле, нужно найти'thing.h 'вдоль пути включения и прочитать Но есть проверка #ifndef _SOMETHING_H_, поэтому содержимое такого файла не будет компилироваться. Таким образом, есть некоторые накладные расходы, но они действительно малы.

1 голос
/ 19 августа 2011

Другой метод, помимо предварительно скомпилированных заголовков, - это идиома брандмауэра компилятора, объясненная здесь:

http://www.gotw.ca/publications/mill04.htm

http://www.gotw.ca/publications/mill05.htm

0 голосов
/ 19 августа 2011

Это может быть проблемой. Как говорили другие, большинство современных компиляторов обрабатывать дело разумно, и только заново откроет файл в вырожденные случаи. Однако, это еще не все, а один из основных Исключением является Microsoft, которую многие люди должны поддерживать. Самое верное решение (если это действительно проблема в вашей среде) заключается в использовать конвенцию Lakos, помещая охранников включения вокруг #include а также в шапке. Это означает, конечно, стандарт Соглашение для генерации охранных имен. (Для внешних включает, заверните их в вашем собственном заголовке, который уважает ваше местное соглашение.) В качестве альтернативы вы можете использовать как охранников, так и #pragma once. охранники всегда будут работать, и большинство компиляторов будут избегать лишних открытий, и #pragma once обычно избегает дополнительных открытий с Microsoft. (#pragma once не может быть надежно реализовано в сложных сетевых ситуации, но пока все ваши файлы находятся на локальном диске, это довольно надежно.)

0 голосов
/ 19 августа 2011

Некоторые компиляторы, особенно Microsoft, имеют директиву #pragma once, которую можно использовать для автоматического пропуска включаемого файла, когда он уже включен. Это устраняет любые потери производительности.

http://en.wikipedia.org/wiki/Pragma_once

0 голосов
/ 19 августа 2011

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

Foo.h

#ifndef FOO_H
#define FOO_H

// whatever

#endif  /* FOO_H */

Во всех файлах, которые должны включать foo.h

#ifndef FOO_H
#include "foo.h"
#endif

Thisпредотвращает многократное открытие foo.h.Конечно, это зависит от того, соблюдает ли каждый конкретное соглашение об именах для своих защитников препроцессора.

Вы не можете сделать это со стандартными заголовками, так как для их защиты препроцессора не существует общего соглашения об именах.* EDIT: После прочтения вашего вопроса, я думаю, вы спрашиваете о том же заголовке, включенном в разные исходные файлы.То, о чем я говорил выше, не поможет с этим.Каждый заголовочный файл все равно нужно будет открыть и включить хотя бы один раз в каждую единицу перевода.Единственный известный мне способ предотвратить это - использовать предварительно скомпилированные заголовки, как указано в его ответе @ scorcher24 .Но я бы держался подальше от этого решения, потому что не существует стандартного способа генерирования предварительно скомпилированных заголовков для разных компиляторов, если время компиляции не является абсолютно непомерным.

0 голосов
/ 19 августа 2011

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

Он в основном собирает все заголовочные файлы и компилирует их в объектный файл, который затем может использоваться компоновщиком.Это очень ускоряет компиляцию.

Незначительный недостаток:

Вам необходимо иметь 1 «верхний колонтитул», который включен в каждый модуль компиляции (.cpp).

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

Это помогает ESP.при использовании библиотек только для заголовков, таких как boost или glm, eigen и т. д.

HTH

...