ヘッダー ユニット、モジュール、プリコンパイル済みヘッダーを比較する

これまでは、次のような #include <vector>ディレクティブを含む標準ライブラリを含めます。 ただし、ヘッダー ファイルが含まれるすべてのソース ファイルによって再処理されるため、ヘッダー ファイルを含めるのはコストがかかります。

プリコンパイル済みヘッダー (PCH) は、それらを 1 回変換して結果を再利用することで、コンパイルを高速化するために導入されました。 ただし、プリコンパイル済みヘッダーをメインに含めるのは困難な場合があります。

C++20 では、ヘッダー ファイルとプリコンパイル済みヘッダーの大幅な改善としてモジュールが導入されました。

ヘッダー ユニットは、ヘッダー ファイルとモジュールの間のギャップを一時的に埋める方法として C++20 で導入されました。 モジュールを使用するようにコードを移行する際に、モジュールの速度と堅牢性の利点の一部が提供されます。

その後、C++23 標準ライブラリでは、標準ライブラリを名前付きモジュールとしてインポートするためのサポートが導入されました。 これは、標準ライブラリを使用する最も高速で最も堅牢な方法です。

さまざまなオプションを整理するために、この記事では、従来 #include のメソッドとプリコンパイル済みヘッダー、ヘッダー ユニット、および名前付きモジュールのインポートを比較します。

次の表は、コンパイラの処理速度と堅牢性で、最も遅く、 #include 最も堅牢で、 import 最も高速かつ最も堅牢です。

メソッド まとめ
#include 1 つの欠点は、マクロと内部実装を公開することです。 内部実装は、多くの場合、アンダースコアで始まる関数や型として公開されます。 これは、何かが内部実装の一部であり、使用しないことを示す規則です。

ヘッダー ファイルは、#includes の順序によって動作が変更されたり、コードが中断されたりする可能性があり、マクロ定義の影響を受けるため、脆弱です。

ヘッダー ファイルのコンパイルが遅い。 特に、ヘッダー ファイルが複数回再処理されるため、複数のファイルに同じファイルが含まれている場合。
プリコンパイル済みヘッダー プリコンパイル済みヘッダー (PCH) は、一連のヘッダー ファイルのコンパイラ メモリ スナップショットを作成することでコンパイル時間を短縮します。 これは、ヘッダー ファイルを繰り返し再構築する際の改善です。

PCH ファイルには、メインを含めにくい制限があります。

PCHファイルは、より #include 高速ですが、より import遅いです.
ヘッダーユニット これは C++20 の新機能で、"適切に動作する" ヘッダー ファイルをモジュールとしてインポートできます。

ヘッダー ユニットは、プリコンパイル済みヘッダー ファイル (PCH) よりも#include高速で、メインが容易で、大幅に小さく、高速です。

ヘッダー ユニットは、名前付きモジュールではマクロが公開されないため、ヘッダー ファイルで定義されているマクロに依存する場合に、名前付きモジュールへの移行に役立つ "中間" ステップです。

ヘッダー ユニットは、名前付きモジュールのインポートよりも遅くなります。

ヘッダー ユニットが組み込まれているときにコマンド ラインで指定されていない限り、ヘッダー ユニットはマクロ定義の影響を受けず、ヘッダー ファイルよりも堅牢になります。

ヘッダー ユニットは、ヘッダー ファイルと同様に定義されたマクロと内部実装を公開しますが、名前付きモジュールでは定義されません。

ファイル サイズの大まかな近似として、250 メガバイトの PCH ファイルは 80 メガバイトのヘッダー ユニット ファイルで表される場合があります。
モジュール これは、機能をインポートするための最速かつ最も堅牢な方法です。

モジュールのインポートのサポートは、C++20 で導入されました。 C++23 標準ライブラリには、このトピックで説明する 2 つの名前付きモジュールが導入されています。

インポート stdすると、標準名 std::vector(. std::cout、ただし、拡張子なし、内部ヘルパーなしなど _Sort_unchecked) が取得され、マクロは取得されません。

マクロやその他の副作用がないため、インポートの順序は関係ありません。

ファイル サイズの大まかな近似として、250 メガバイトの PCH ファイルは 80 メガバイトのヘッダー ユニット ファイルで表され、25 メガバイト のモジュールで表される場合があります。

名前付きモジュールは、名前付きモジュールがファイルと.objファイルに.ifcコンパイルされるときに、モジュールのインポート時にすばやく読み込むことができるソース コードの構造化表現を生成するため、高速です。 名前付きモジュールが順序に依存せず、マクロに依存しないため、コンパイラはファイルを出力する .ifc 前に (名前解決など) 何らかの作業を行うことができます。そのため、モジュールのインポート時にこの作業を行う必要はありません。 これに対し、ヘッダー ファイルを使用 #includeする場合は、その内容を前処理し、すべての翻訳単位で繰り返しコンパイルする必要があります。

プリコンパイル済みヘッダー (コンパイラ メモリ スナップショット) は、これらのコストを軽減できますが、名前付きモジュールは軽減できません。

アプリで C++20 機能と C++23 標準ライブラリを使用できる場合は、名前付きモジュールを使用します。

C++20 機能を使用できるが、時間の経過と共にモジュールに移行する場合は、中間でヘッダー ユニットを使用します。

C++20 機能を使用できない場合は、プリコンパイル済みヘッダーを使用 #include して検討してください。

関連項目

プリコンパイル済みヘッダー ファイル
C++ のモジュールの概要
チュートリアル: モジュールを使用して C++ 標準ライブラリをインポートする
チュートリアル: STL ライブラリをヘッダ ーユニットとしてインポートする
チュートリアル: Visual C++ プロジェクトでヘッダー ユニットをビルドしてインポートする