いくつかの理由
ヘッダーファイル
コンパイルユニットごとに、数百または数千のヘッダーを(1)ロードして(2)コンパイルする必要があります。プリプロセッサは、ヘッダーのコンパイル結果がすべてのコンパイルユニット間で異なる可能性があることを保証するため、通常、それらすべてをコンパイルユニットごとに再コンパイルする必要があります。(マクロは、ヘッダーの内容を変更する1つのコンパイル単位で定義できます)。
これはおそらく、それがすべてのコンパイル単位のためにコンパイルされるコードの膨大な量を必要とし、さらに、すべてのヘッダは、(それを含むすべてのコンパイル単位に一度)を複数回コンパイルされなければならないように、主な理由。
リンク
コンパイルしたら、すべてのオブジェクトファイルをリンクする必要があります。これは基本的にモノリシックプロセスであり、あまり並列化できず、プロジェクト全体を処理する必要があります。
解析中
構文は解析が非常に複雑で、コンテキストに大きく依存し、明確にすることは非常に困難です。これには時間がかかります。
テンプレート
C#ではList<T>
、プログラム内にリストのインスタンス化がいくつあるかに関係なく、コンパイルされるのはだけです。C ++では、vector<int>
はから完全に分離したタイプvector<float>
であり、それぞれを個別にコンパイルする必要があります。
これに加えて、テンプレートは、コンパイラが解釈する必要のある完全なチューリング完全な「サブ言語」を構成し、これは途方もなく複雑になる可能性があります。比較的単純なテンプレートメタプログラミングコードでも、数十および数十のテンプレートのインスタンス化を作成する再帰的なテンプレートを定義できます。テンプレートはまた、途方もなく長い名前を持つ非常に複雑な型をもたらす可能性があり、リンカーに多くの追加作業を追加します。(多くのシンボル名を比較する必要があり、これらの名前が何千もの文字に成長する可能性がある場合、それはかなり高価になる可能性があります)。
そしてもちろん、テンプレートは通常ヘッダーで定義する必要があるため、ヘッダーファイルの問題は悪化します。つまり、コンパイル単位ごとにはるかに多くのコードを解析してコンパイルする必要があります。通常のCコードでは、ヘッダーには通常、前方宣言のみが含まれますが、実際のコードはほとんど含まれません。C ++では、ほとんどすべてのコードがヘッダーファイルに存在することも珍しくありません。
最適化
C ++では、非常に劇的な最適化が可能です。C#またはJavaでは、クラスを完全に削除することはできません(リフレクションのためにクラスを削除する必要があります)が、単純なC ++テンプレートメタプログラムでも数十または数百のクラスを簡単に生成でき、それらはすべてインライン化され、最適化で再び削除されます。段階。
さらに、C ++プログラムはコンパイラーによって完全に最適化する必要があります。C#プログラムは、JITコンパイラに依存して、ロード時に追加の最適化を実行できます。C++では、このような「2番目のチャンス」はありません。コンパイラが生成するものは、取得するのと同じくらい最適化されています。
機械
C ++は、Javaまたは.NETのバイトコード(特にx86の場合)の使用よりも多少複雑になる可能性があるマシンコードにコンパイルされます。(これは、コメントなどで言及されたという理由だけで完全性から言及されています。実際には、このステップは、総コンパイル時間のごく一部以上を占めることはほとんどありません)。
結論
これらの要素のほとんどは、実際にかなり効率的にコンパイルされるCコードによって共有されます。C ++では解析ステップがはるかに複雑で、かなり時間がかかる可能性がありますが、主な違反者はおそらくテンプレートです。それらは有用であり、C ++をはるかに強力な言語にしますが、コンパイル速度の点でも犠牲になります。