Предположения
Одним из преимуществ библиотек только для заголовков для C ++ является то, что их не нужно компилировать отдельно.
В C и C ++
inline
имеет смысл только если функция определена в заголовочном файле *.Традиционно в C использовался макет .c / .h, где заголовок представляет минимальный открытый интерфейс модуля перевода. Точно так же .cpp / hpp.
Вопрос
Являются ли библиотеки, использующие только заголовки, как правило, более эффективными с точки зрения кода и времени выполнения, чем традиционная схема? Если так, это из-за обширного встраивания или других оптимизаций?
* - определение функции в заголовке позволяет компилятору видеть реализацию во время компиляции любого модуля перевода и практически делает возможным встраивание кода
Ответы:
Нет, это не является преимуществом, скорее наоборот - основная часть библиотеки должна компилироваться так часто, как она включается, а не один раз. Это обычно увеличивает время компиляции. Однако, если вы ссылаетесь на преимущества, перечисленные здесь, в Википедии : в этой статье говорится об уменьшении административных издержек, связанных со всем процессом сборки, упаковки и развертывания.
Это зависит от системы компилятор / компоновщик, но я думаю, что для большинства существующих компиляторов C и C ++ это действительно так.
Это в основном правильно. Заголовки классов C ++ часто содержат больше, чем минимальный открытый интерфейс - они обычно содержат также много закрытых вещей. Чтобы смягчить это, используются такие вещи, как идиома PIMPL . Это что-то вроде «противоположности» библиотеки, содержащей только заголовки, она пытается минимизировать необходимое содержимое заголовка.
Но чтобы ответить на ваш главный вопрос: это компромисс. Чем больше библиотечного кода помещается в заголовочные файлы, тем больше у компилятора шансов оптимизировать код по скорости (если это действительно произойдет, или если увеличение заметно, это совершенно другой вопрос). С другой стороны, слишком большое количество кода в заголовках увеличивает время компиляции. Особенно в больших проектах на C ++ это может стать серьезной проблемой, см. «Разработка программного обеспечения для крупномасштабного C ++» Джона Лакоса - хотя книга немного устарела и некоторые из описанных здесь проблем решаются современными компиляторами, общие идеи / решения остаются в силе.
В частности, когда вы не используете стабильную (стороннюю) библиотеку, но разрабатываете свои собственные библиотеки во время своего проекта, время компиляции становится очевидным. Каждый раз, когда вы что-то меняете в lib, вы должны изменить заголовочный файл, который вызовет перекомпиляцию и связывание всех зависимых модулей.
ИМХО популярность библиотек только с заголовками обусловлена популярностью шаблонного метапрограммирования. Для большинства компиляторов шаблонные библиотеки должны иметь только заголовок, потому что компилятор может запустить основной процесс компиляции только при условии указания параметров типа, а для полной компиляции и оптимизации компилятор должен видеть «оба сразу» - код библиотеки плюс шаблон значения параметров. Это делает невозможным (или, по крайней мере, трудным) создание каких-либо «предварительно скомпилированных» модулей компиляции для такой библиотеки.
источник
Что ж, давайте сначала опровергнем некоторые из ваших предположений:
Компиляция вещей по отдельности означает, что потенциально не нужно перекомпилировать все, если изменяется только часть.
Итак, недостаток вместо преимущества.
Да, единственный
inline
оставшийся эффект - это исключение из правила одного определения .Горе вам, если эти определения в любом случае отличаются.
Итак, если функция является внутренней по отношению к модулю компиляции, отметьте ее
static
. Это также делает встраивание более вероятным, так как функция должна быть доступна для его встраивания.Тем не менее, взгляните на оптимизацию времени соединения, поддерживаемую по крайней мере MSVC ++, gcc и clang.
Что ж, только представление минимального интерфейса, безусловно, является одной из целей - добиться более высокой стабильности API и ABI и минимизировать время компиляции.
Тем не менее, классы C ++ на самом деле не приспособлены к этому, поскольку все частные биты просачиваются в заголовок, как и защищенные, независимо от того, хотите ли вы получить их из этого или нет.
Дизайн-шаблон PIMPL предназначен для уменьшения таких деталей.
Часть, где разделение интерфейса и реализации полностью терпит неудачу в C ++, является шаблонами.
Комитет пытался сделать что-то с экспортированными шаблонами , но это было заброшено как слишком сложное и не очень работающее.
Теперь они работают над правильной модульной системой , хотя она идет медленно. Это значительно сокращает время компиляции, а также должно повысить стабильность API и ABI за счет уменьшения их поверхности.
Библиотеки только для заголовков могут быть более эффективными с точки зрения размера кода и времени выполнения, хотя это зависит от того, используется ли библиотека совместно, насколько она используется, как и каким образом, и является ли встраивание решающим преимуществом в этом конкретном случае.
И причина, по которой встраивание так важно для оптимизации, не в том, что встраивание само по себе является таким мощным стимулом, а из-за возможностей постоянного распространения и дальнейшей оптимизации, которые он открывает.
источник