Подтвердить что ты не робот

Сколько накладных объявлений влияет на время компиляции?

Мне очень интересны некоторые исследования или эмпирические данные, которые показывают сравнение времени компиляции между двумя проектами на С++, которые являются одинаковыми, за исключением того, что, если это возможно, используются прямые объявления, а другие - нет.

Насколько сильно можно пересылать декларации, изменяют время компиляции по сравнению с полным?

#include "myClass.h"

против.

class myClass;

Есть ли какие-либо исследования, которые исследуют это?

Я понимаю, что это неопределенный вопрос, который сильно зависит от проекта. Я не ожидаю, что для ответа будет трудным. Скорее, я надеюсь, что кто-то сможет направить меня на исследование об этом.

В проекте, о котором я особенно беспокоюсь, содержится около 1200 файлов. Каждый cpp в среднем содержит 5 заголовков. Каждый заголовок содержит в среднем 5 заголовков. Это регрессирует примерно на 4 уровня. Казалось бы, для каждого скомпилированного cpp около 300 заголовков должны быть открыты и проанализированы несколько раз. (В дереве include есть много дубликатов.) Есть защитники, но файлы все еще открыты. Каждый cpp отдельно компилируется с помощью gcc, поэтому кэширование заголовков отсутствует.

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

Спасибо за любую информацию.

4b9b3361

Ответ 1

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

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

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

Изменить. Учитывая ваш комментарий выше, я хотел бы указать, что ВСЕГДА медленнее включать заголовочный файл, чем переслать объявление. Каждый раз, когда вы включаете заголовок, вы часто требуете загрузки с диска, чтобы узнать, что защитники заголовков означают, что ничего не происходит. Это будет тратить огромное количество времени и действительно является ОЧЕНЬ тупым правилом, чтобы принести.

Изменить 2. Жестких данных довольно трудно получить. В некотором роде я работал над проектом, который не был строгим в отношении его заголовка, и время сборки составляло примерно 45 минут на 512 Мб ОЗУ P3-500Mhz (это было некоторое время назад). Проведя 2 недели, сократив кошмар включительно (используя передовые декларации) мне удалось получить код, чтобы построить чуть меньше 4 минут. Впоследствии использование передовых деклараций стало, когда это возможно, правилом.

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

Я также отмечаю много других людей, превозносящих достоинства предварительно скомпилированных заголовков (PCH). У них есть свое место, и они действительно могут помочь, но они действительно не должны использоваться в качестве альтернативы надлежащей декларации. В противном случае модификации файлов заголовков могут вызвать проблемы с перекомпиляцией большого количества файлов (как упоминалось выше), а также инициировать восстановление PCH. PCH могут обеспечить большую победу для таких вещей, как готовые библиотеки, но они не являются основанием не использовать правильные декларации.

Ответ 2

Взгляните в John Lakos отлично Large Scale С++ Design book - Я думаю, что у него есть некоторые цифры для форвардной декларации, глядя на то, что происходит если вы включили N уровней заголовков M глубоко.

Если вы не используете форвардные объявления, то помимо увеличения общего времени сборки из чистого исходного дерева, он также значительно увеличивает время нарастания, потому что заголовочные файлы включаются без необходимости. Скажем, у вас есть 4 класса: A, B, C и D. C использует A и B в своей реализации (т.е. В C.cpp), а D использует C в своей реализации. Интерфейс D вынужден включать C.h из-за этого правила "без прямого объявления". Аналогично, C.h вынужден включать A.h и B.h, поэтому, когда A или B изменяются, D.cpp необходимо перестроить, даже если он не имеет прямой зависимости. По мере того, как проект масштабируется, это означает, что если вы касаетесь любого заголовка, это будет иметь огромное влияние на создание огромного количества кода, который будет восстановлен, что просто не нужно.

Чтобы иметь правило, которое запрещает форвардную декларацию (в моей книге), очень плохой практикой. Это собирается потратить огромное количество времени для разработчиков, чтобы не получить прибыль. Общее правило должно состоять в том, что если интерфейс класса B зависит от класса A, то он должен включать A.h, иначе forward объявите его. На практике "зависит от" означает наследование, используется как переменная-член или "использует любые методы". Идиома Pimpl является широко распространенным и хорошо понятным методом для скрытия реализации от интерфейса и позволяет значительно сократить объем перестройки, необходимый для вашей кодовой базы.

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

Ответ 3

#include "myClass.h"

- 1..n строк

class myClass;

- 1 строка.

Вы сэкономите время, если все ваши заголовки не состоят из 1 лайнера. Поскольку влияние самой компиляции не влияет (прямое указание - это просто способ сказать компилятору, что определенный конкретный символ будет определен во время ссылки и будет возможен, только если компилятору не нужны данные из этого символа (например, размер данных )), время чтения включенных файлов будет сохранено каждый раз, когда вы заменяете его перекрестными ссылками. Для этого нет регулярной меры, так как это значение для каждого проекта, но рекомендуется для больших проектов на С++ (см. Крупномасштабная разработка программного обеспечения на С++/John Lakos для получения дополнительной информации об трюках для управления большими проектами на С++, даже если некоторые из них датированы)

Еще один способ ограничить время, прошедшее компилятором в заголовках, - это предварительно скомпилированные заголовки.

Ответ 4

Вы задали очень общий вопрос, который вызвал некоторые очень хорошие общие ответы. Но ваш вопрос был не в вашей реальной проблеме:

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

У нас есть информация о проекте, но недостаточно:

В проекте, о котором я особенно беспокоюсь, содержится около 1200 файлов. Каждый cpp в среднем содержит 5 заголовков. Каждый заголовок содержит в среднем 5 заголовков. Это регрессирует примерно на 4 уровня. Казалось бы, для каждого скомпилированного cpp около 300 заголовков должны быть открыты и проанализированы несколько раз. (В дереве include есть много дубликатов.) Есть защитники, но файлы все еще открыты. Каждый cpp отдельно компилируется с помощью gcc, поэтому кэширование заголовков отсутствует.

Что вы сделали для использования gcc precompiled headers? Какая разница во время компиляции?

Сколько времени требуется, чтобы скомпилировать чистую сборку? Как долго ваши типичные (нечистые/инкрементные) сборки? Если, как в примере Джеймса Макнеллиса в комментариях, время сборки меньше минуты:

Последний большой проект на С++, над которым я работал, был порядка 1 миллиона SLOC (не включая сторонние библиотеки).... Мы не пользовались передовыми объявлениями вообще, и все это строилось за 10 минут. Инкрементные перестройки составляли порядка секунд.

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

Возьмите небольшую часть своего проекта и преобразуйте его в то, что вам бы хотелось. Измерьте различия во времени компиляции между неизмененными и преобразованными версиями этого образца. Не забудьте коснуться (или эквивалент make -assume-new) различных наборов файлов для представления реальных сборок, с которыми вы столкнулись во время работы.

Покажите вашему работодателю, как вы будете более продуктивны.

Ответ 5

Умм, вопрос так неясен. И это зависит, чтобы быть простым.

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