次の方法で共有


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

これまでは、 #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::vectorstd::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++ プロジェクトでヘッダー ユニットをビルドしてインポートする