Partilhar via


Comparar unidades de cabeçalho, módulos e cabeçalhos pré-compilados

Historicamente, você incluiria a biblioteca padrão com uma diretiva como #include <vector>. No entanto, é caro incluir arquivos de cabeçalho porque eles são reprocessados por todos os arquivos de origem que os incluem.

Cabeçalhos pré-compilados (PCH) foram introduzidos para acelerar a compilação, traduzindo-os uma vez e reutilizando o resultado. Mas cabeçalhos pré-compilados podem ser difíceis de manter.

Em C++20, os módulos foram introduzidos como uma melhoria significativa em arquivos de cabeçalho e cabeçalhos pré-compilados.

As unidades de cabeçalho foram introduzidas no C++20 como uma forma de preencher temporariamente a lacuna entre arquivos de cabeçalho e módulos. Eles fornecem alguns dos benefícios de velocidade e robustez dos módulos, enquanto você migra seu código para usar módulos.

Em seguida, a biblioteca padrão C++23 introduziu suporte para importar a biblioteca padrão como módulos nomeados. Esta é a maneira mais rápida e robusta de consumir a biblioteca padrão.

Para ajudá-lo a classificar as diferentes opções, este artigo compara o método tradicional #include com cabeçalhos pré-compilados, unidades de cabeçalho e importação de módulos nomeados.

A tabela a seguir é organizada pela velocidade de processamento e robustez do compilador, sendo #include a mais lenta e menos robusta, e import sendo a mais rápida e robusta.

Método Resumo
#include Uma desvantagem é que eles expõem macros e implementação interna. A implementação interna é frequentemente exposta como funções e tipos que começam com um sublinhado. Essa é uma convenção para indicar que algo faz parte da implementação interna e não deve ser usado.

Os arquivos de cabeçalho são frágeis porque a ordem de #includes pode modificar o comportamento ou quebrar o código e são afetados por definições de macro.

Compilação lenta de arquivos de cabeçalho. Particularmente quando vários arquivos incluem o mesmo arquivo porque, em seguida, o arquivo de cabeçalho é reprocessado várias vezes.
Cabeçalho pré-compilado Um cabeçalho pré-compilado (PCH) melhora o tempo de compilação criando um instantâneo de memória do compilador de um conjunto de arquivos de cabeçalho. Esta é uma melhoria na reconstrução repetida de arquivos de cabeçalho.

Os arquivos PCH têm restrições que os tornam difíceis de manter.

Os arquivos PCH são mais rápidos que #include, mas mais lentos que import.
Unidades de cabeçalho Este é um novo recurso no C++20 que permite importar arquivos de cabeçalho 'bem comportados' como módulos.

As unidades de cabeçalho são mais rápidas do que #include, e são mais fáceis de manter, significativamente menores e também mais rápidas do que os arquivos de cabeçalho pré-compilados (PCH).

As unidades de cabeçalho são uma etapa "intermediária" destinada a ajudar na transição para módulos nomeados nos casos em que você confia em macros definidas em arquivos de cabeçalho, uma vez que os módulos nomeados não expõem macros.

As unidades de cabeçalho são mais lentas do que a importação de um módulo nomeado.

As unidades de cabeçalho não são afetadas pelas definições de macro, a menos que sejam especificadas na linha de comando quando a unidade de cabeçalho é construída, tornando-as mais robustas do que os arquivos de cabeçalho.

Os módulos de cabeçalho expõem as macros e as implementações internas definidas neles, tal como faz o ficheiro de cabeçalho, coisa que os módulos nomeados não fazem.

Como uma aproximação aproximada do tamanho do arquivo, um arquivo PCH de 250 megabytes pode ser representado por um arquivo de unidade de cabeçalho de 80 megabytes.
Módulos Esta é a maneira mais rápida e robusta de importar funcionalidades.

O suporte para importação de módulos foi introduzido no C++20. A biblioteca padrão C++23 apresenta os dois módulos nomeados descritos neste tópico.

Ao importar std, obtém-se os nomes padrão, tais como std::vector, std::cout, mas sem extensões, sem assistentes internos como _Sort_unchecked e sem macros.

A ordem das importações não importa, porque não há efeitos macro ou outros efeitos colaterais.

Como uma aproximação aproximada do tamanho do arquivo, um arquivo PCH de 250 megabytes pode ser representado por um arquivo de unidade de cabeçalho de 80 megabytes, que pode ser representado por um módulo de 25 megabytes.

Os módulos nomeados são mais rápidos porque quando um módulo nomeado é compilado em um .ifc arquivo e um .obj arquivo, o compilador emite uma representação estruturada do código-fonte que pode ser carregada rapidamente quando o módulo é importado. O compilador pode fazer algum trabalho (como resolução de nomes) antes de emitir o arquivo por causa de como os .ifc módulos nomeados são independentes de ordem e macro - então esse trabalho não precisa ser feito quando o módulo é importado. Em contraste, quando um ficheiro de cabeçalho é consumido com #include, o seu conteúdo deve ser preprocessado e compilado repetidamente em cada unidade de tradução.

Os cabeçalhos pré-compilados, que são instantâneos de memória do compilador, podem reduzir esses custos, mas não tão bem quanto os módulos nomeados.

Se você puder usar os recursos do C++20 e a biblioteca padrão do C++23 em seu aplicativo, use módulos nomeados.

Se você pode usar recursos do C++20, mas deseja fazer a transição ao longo do tempo para módulos, use unidades de cabeçalho nesse ínterim.

Se você não puder usar os recursos do C++20, use #include e considere cabeçalhos pré-compilados.

Ver também

Arquivos de cabeçalho pré-compilados
Visão geral dos módulos em C++
Tutorial: Importar a biblioteca padrão C++ usando módulos
Passo a passo: Importar bibliotecas STL como unidades de cabeçalho
Passo a passo: Criar e importar unidades de cabeçalho em seus projetos do Microsoft C++