Поделиться через


Сравнение блоков заголовков, модулей и предварительно скомпилированных заголовков

Исторически вы включили стандартную библиотеку с директивой, например #include <vector>. Тем не менее, это дорого включить файлы заголовков, так как они повторно обрабатывается каждым исходным файлом, который включает их.

Предварительно скомпилированные заголовки (PCH) были представлены для ускорения компиляции путем их преобразования один раз и повторного выполнения результата. Но предварительно скомпилированные заголовки могут быть трудно поддерживать.

В C++20 модули появились в качестве значительного улучшения файлов заголовков и предварительно скомпилированных заголовков.

Блоки заголовков были представлены в C++20 как способ временно мостить разрыв между файлами заголовков и модулями. Они предоставляют некоторые преимущества скорости и надежности модулей, при переносе кода на использование модулей.

Затем стандартная библиотека C++23 представила поддержку импорта стандартной библиотеки в виде именованных модулей. Это самый быстрый и надежный способ использования стандартной библиотеки.

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

Следующая таблица организована скоростью обработки компилятора и надежностью, что является #include самым медленным и наименее надежным и import самым быстрым и самым надежным.

Метод Итоги
#include Одним из недостатков является то, что они предоставляют макросы и внутреннюю реализацию. Внутренняя реализация часто предоставляется как функции и типы, начинающиеся с подчеркивания. Это соглашение, указывающее, что что-то является частью внутренней реализации и не должно использоваться.

Файлы заголовков являются хрупкими, так как порядок #includes может изменять поведение или код останова и влиять на определения макросов.

Файлы заголовков медленно компиляции. Особенно если несколько файлов включают один и тот же файл, так как затем файл заголовка повторно обрабатывается несколько раз.
Предкомпилированный заголовок Предварительно скомпилированный заголовок (PCH) улучшает время компиляции путем создания моментального снимка памяти компилятора набора файлов заголовков. Это улучшение многократного перестроения файлов заголовков.

PCH-файлы имеют ограничения, которые затрудняют их обслуживание.

PCH-файлы быстрее #include , чем медленнее import.
Единицы заголовка Это новая функция в C++20, которая позволяет импортировать файлы заголовков "хорошо себя" в виде модулей.

Единицы заголовков быстрее, чем #includeи проще поддерживать, значительно меньше, а также быстрее, чем предварительно скомпилированные файлы заголовков (PCH).

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

Блоки заголовков медленнее импорта именованного модуля.

Блоки заголовков не влияют на макросы, если они не указаны в командной строке, когда блок заголовка построен более надежным, чем файлы заголовков.

Блоки заголовков предоставляют макросы и внутреннюю реализацию, определенные в них так же, как файл заголовка, который именованные модули не делают.

Как грубое приближение размера файла, 250-мегабайтный PCH-файл может быть представлен 80-мегабайтным файлом заголовка заголовка.
Модули Это самый быстрый и надежный способ импорта функциональных возможностей.

Поддержка импорта модулей появилась в C++20. Стандартная библиотека C++23 представляет два именованных модуля, описанных в этом разделе.

При импорте stdвы получаете такие стандартные имена, как std::vector, std::coutно нет расширений, без внутренних вспомогательных элементов, таких как _Sort_unchecked, и без макросов.

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

Как грубое приближение размера файла, 250-мегабайтовый PCH-файл может быть представлен 80-мегабайтным файлом заголовка заголовка, который может быть представлен 25-мегабайтным модулем.

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

Предварительно скомпилированные заголовки, которые являются моментальными снимками памяти компилятора, могут снизить эти затраты, но не так же, как и именованные модули.

Если в приложении можно использовать функции C++20 и стандартную библиотеку C++23, используйте именованные модули.

Если вы можете использовать функции C++20, но хотите с течением времени переходить на модули, используйте единицы заголовков в промежуточном периоде.

Если вы не можете использовать функции C++20, используйте #include и рассмотрите предварительно скомпилированные заголовки.

См. также

Файлы предкомпилированных заголовков
Обзор модулей в C++
Руководство. Импорт стандартной библиотеки C++ с помощью модулей
Пошаговое руководство. Импорт библиотек STL в качестве блоков заголовков
Создание и импорт блоков заголовков в проектах Visual C++