ヘッダー ユニット、モジュール、プリコンパイル済みヘッダーを比較する
これまでは、 #include <vector>
などのディレクティブを含む標準ライブラリを含めます。 ただし、ヘッダー ファイルが含まれるすべてのソース ファイルによって再処理されるため、ヘッダー ファイルを含めるのはコストがかかります。
プリコンパイル済みヘッダー (PCH) は、それらを 1 回変換して結果を再利用することで、コンパイルを高速化するために導入されました。 ただし、プリコンパイル済みヘッダーは保守が困難な場合があります。
C++20 では、ヘッダー ファイルとプリコンパイル済みヘッダーの大幅な改善としてモジュールが導入されました。
ヘッダー ユニットは、ヘッダー ファイルとモジュールの間のギャップを一時的に埋める方法として C++20 で導入されました。 モジュールを使用するようにコードを移行する際に、モジュールの速度と堅牢性の利点の一部が提供されます。
その後、C++23 標準ライブラリでは、標準ライブラリを名前付きモジュールとしてインポートするためのサポートが導入されました。 これは、標準ライブラリを使用する最も高速で最も堅牢な方法です。
さまざまなオプションを整理するために、この記事では、従来の #include
メソッドとプリコンパイル済みヘッダー、ヘッダー ユニット、および名前付きモジュールのインポートを比較します。
次の表は、コンパイラの処理速度と堅牢性によって整理されています。 #include
は最も低速で最も堅牢で、 import
が最も高速で最も堅牢です。
メソッド | まとめ |
---|---|
#include |
1 つの欠点は、マクロと内部実装を公開することです。 内部実装は、多くの場合、アンダースコアで始まる関数や型として公開されます。 これは、何かが内部実装の一部であり、使用しないことを示す規則です。 ヘッダー ファイルは、#includes の順序によって動作が変更されたり、コードが中断されたりする可能性があり、マクロ定義の影響を受けるため、脆弱です。 ヘッダー ファイルのコンパイルが遅い。 特に、ヘッダー ファイルが複数回再処理されるため、複数のファイルに同じファイルが含まれている場合。 |
プリコンパイル済みヘッダー | プリコンパイル済みヘッダー (PCH) は、一連のヘッダー ファイルのコンパイラ メモリ スナップショットを作成することでコンパイル時間を短縮します。 これは、ヘッダー ファイルを繰り返し再構築する際の改善です。 PCH ファイルには、保守が困難な制限があります。 PCH ファイルは #include よりも高速ですが、 import よりも低速です。 |
ヘッダーユニット | これは C++20 の新機能で、"適切に動作する" ヘッダー ファイルをモジュールとしてインポートできます。 ヘッダー ユニットは、 #include よりも高速であり、保守が容易で、大幅に小さく、プリコンパイル済みのヘッダー ファイル (PCH) よりも高速です。ヘッダー ユニットは、名前付きモジュールではマクロが公開されないため、ヘッダー ファイルで定義されているマクロに依存する場合に、名前付きモジュールへの移行に役立つ "中間" ステップです。 ヘッダー ユニットは、名前付きモジュールのインポートよりも遅くなります。 ヘッダー ユニットが組み込まれているときにコマンド ラインで指定されていない限り、ヘッダー ユニットはマクロ定義の影響を受けず、ヘッダー ファイルよりも堅牢になります。 ヘッダー ユニットは、ヘッダー ファイルと同様に定義されたマクロと内部実装を公開しますが、名前付きモジュールでは定義されません。 ファイル サイズの大まかな近似として、250 メガバイトの PCH ファイルは 80 メガバイトのヘッダー ユニット ファイルで表される場合があります。 |
モジュール | これは、機能をインポートするための最速かつ最も堅牢な方法です。 モジュールのインポートのサポートは、C++20 で導入されました。 C++23 標準ライブラリには、このトピックで説明する 2 つの名前付きモジュールが導入されています。 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) をインポートする
チュートリアル: STL ライブラリをヘッダ ーユニットとしてインポートする
チュートリアル: Visual C++ プロジェクトでヘッダー ユニットをビルドしてインポートする