Compartir a través de


Comparación de unidades de encabezado, módulos y encabezados precompilados

Históricamente, incluiría la biblioteca estándar con una directiva como #include <vector>. Sin embargo, es costoso incluir archivos de encabezado porque cada archivo de origen los vuelve a procesar.

Los encabezados precompilados (PCH) se introdujeron para acelerar la compilación traduciéndolos una vez y reutilizando el resultado. Pero los encabezados precompilados pueden ser difíciles de mantener.

En C++20, los módulos se introdujeron como una mejora significativa en los archivos de encabezado y los encabezados precompilados.

Las unidades de encabezado se introdujeron en C++20 como una manera de salvar temporalmente la brecha entre los archivos de encabezado y los módulos. Proporcionan algunas de las ventajas de velocidad y solidez de los módulos, mientras se migra el código para usar módulos.

A continuación, la biblioteca estándar de C++23 introdujo compatibilidad para importar la biblioteca estándar como módulos con nombre. Esta es la forma más rápida y sólida de consumir la biblioteca estándar.

Para ayudarle a ordenar las distintas opciones, en este artículo se compara el método tradicional #include con los encabezados precompilados, las unidades de encabezado y la importación de módulos con nombre.

La tabla siguiente se organiza mediante la velocidad y la solidez del procesamiento del compilador, siendo #include la más lenta y menos robusta, y import siendo la más rápida y sólida.

Método Resumen
#include Una desventaja es que exponen macros e implementación interna. La implementación interna a menudo se expone como funciones y tipos que comienzan con un carácter de subrayado. Es una convención para indicar que algo forma parte de la implementación interna y no debe usarse.

Los archivos de encabezado son frágiles porque el orden de #includes puede modificar el comportamiento o interrumpir el código y se ve afectado por las definiciones de macro.

Compilación lenta de archivos de encabezado. Especialmente cuando varios archivos incluyen el mismo archivo porque el archivo de encabezado se vuelve a procesar varias veces.
Encabezado precompilado Un encabezado precompilado (PCH) mejora el tiempo de compilación mediante la creación de una instantánea de memoria del compilador de un conjunto de archivos de encabezado. Se trata de una mejora en la regeneración repetida de archivos de encabezado.

Los archivos PCH tienen restricciones que dificultan su mantenimiento.

Los archivos PCH son más rápidos que #include pero más lentos que import.
Unidades de encabezado Se trata de una nueva característica de C++20 que permite importar archivos de encabezado "bien comportados" como módulos.

Las unidades de encabezado son más rápidas que #includey son más fáciles de mantener, significativamente más pequeñas y también más rápidas que los archivos de encabezado precompilados (PCH).

Las unidades de encabezado son un paso "entre" diseñado para ayudar a realizar la transición a módulos con nombre en casos en los que se basan en macros definidas en archivos de encabezado, ya que los módulos con nombre no exponen macros.

Las unidades de encabezado son más lentas que importar un módulo con nombre.

Las unidades de encabezado no se ven afectadas por las definiciones de macro, a menos que se especifiquen en la línea de comandos cuando la unidad de encabezado esté integrada, lo que las convierte en más sólidas que los archivos de encabezado.

Las unidades de encabezado exponen las macros y la implementación interna definidas en ellas igual que lo hacen los archivos de encabezado, que los módulos con nombre no.

Como aproximación aproximada del tamaño del archivo, un archivo PCH de 250 megabytes podría representarse mediante un archivo de unidad de encabezado de 80 megabytes.
Módulos Esta es la forma más rápida y sólida de importar la funcionalidad.

La compatibilidad con la importación de módulos se introdujo en C++20. La biblioteca estándar de C++23 presenta los dos módulos con nombre descritos en este tema.

Al importar std, obtendrá los nombres estándar, como std::vector, std::cout, pero sin extensiones, ningún asistente interno como _Sort_unchecked, y ninguna macro.

El orden de las importaciones no importa porque no hay ninguna macro u otros efectos secundarios.

Como aproximación aproximada del tamaño del archivo, un archivo PCH de 250 megabytes podría representarse mediante un archivo de unidad de encabezado de 80 megabytes, que podría representarse mediante un módulo de 25 megabytes.

Los módulos con nombre son más rápidos porque cuando se compila un módulo con nombre en un .ifc archivo y un .obj archivo, el compilador emite una representación estructurada del código fuente que se puede cargar rápidamente cuando se importa el módulo. El compilador puede realizar algún trabajo (como la resolución de nombres) antes de emitir el .ifc archivo debido a cómo los módulos con nombre son independientes del orden e independientes de macros, por lo que este trabajo no tiene que realizarse cuando se importa el módulo. Por el contrario, cuando se consume un archivo de encabezado con #include, su contenido debe preprocesarse y compilarse de nuevo y de nuevo en cada unidad de traducción.

Los encabezados precompilados, que son instantáneas de memoria del compilador, pueden mitigar esos costos, pero no así como los módulos con nombre.

Si puedes usar las características de C++20 y la biblioteca estándar de C++23 en la aplicación, usa módulos con nombre.

Si puede usar las características de C++20, pero desea realizar la transición a lo largo del tiempo a los módulos, use las unidades de encabezado provisionalmente.

Si no puede usar características de C++20, use #include y considere la posibilidad de precompilar encabezados.

Consulte también

Archivos de encabezado precompilado
Información general de los módulos en C++
Tutorial: Importación de la biblioteca estándar de C++ mediante módulos
Tutorial: Importación de bibliotecas STL como unidades de encabezado
Tutorial: Compilación e importación de unidades de encabezado en proyectos de Visual C++