ヘッダーのみのライブラリはより効率的ですか?


48

仮定

  1. C ++のヘッダー専用ライブラリの利点の1つは、個別にコンパイルする必要がないことです。

  2. CおよびC ++ inlineでは、関数がヘッダーファイルで定義されている場合にのみ意味があります*。

  3. 従来、Cでは、ヘッダーが翻訳単位の最小限のパブリックインターフェイスを表す.c / .hレイアウトが使用されてきました。同様に、.cpp / hpp。

質問

一般に、ヘッダーのみのライブラリは、従来のレイアウトよりもコードおよび実行時間の面で効率的ですか?もしそうなら、これは広範なインライン展開または他の最適化のためですか?

*-ヘッダーで関数を定義することで、コンパイラーは翻訳単位のコンパイル中に実装を確認でき、実際にインライン化コードが可能になります


2
多くの最新のC ++リンカー(GCC、MSVC、ICCなど)が別々の翻訳単位にまたがってコードをインライン化できることに驚くでしょう。リンカーの最適化が私の期待に反し、とにかくインライン化できた回数を考えると、効率性の観点では「一般的にいいえ」と言います(ヘッダーでインライン化するか、別の静的リンクライブラリで実装を提供できるdylibコンテキストを除外します) 。しかし、ヘッダーのみのライブラリーは、インターフェースと実装の両方で安定していれば、新しいプロジェクトに簡単にデプロイできるため、セクシーになります。

1
これが完全な答えに値することはわかりませんが、ヘッダーのみのライブラリの大きな利点の1つは、インストールと使用が簡単なことです:ダウンロード、#include "lib.h(pp)"、完了。
-WeRelic

回答:


44

C ++のヘッダーのみのライブラリの利点の1つは、それらを個別にコンパイルする必要がないことです。

いいえ、それは利点ではなく、まったく逆です-ライブラリの主要部分は、一度だけではなく、インクルードされるたびにコンパイルする必要があります。通常、これによりコンパイル時間が長くなります。ただし、Wikipediaのここに挙げられている利点について言及している場合、その記事は、ビルド、パッケージ化、および展開プロセス全体に関する管理オーバーヘッドの削減について述べています。

CおよびC ++では、関数がヘッダーファイルで定義されている場合にのみインラインが有効です*

これはコンパイラ/リンカーシステムに依存しますが、ほとんどの既存のCおよびC ++コンパイラではこれが当てはまると思います。

従来、Cでは、ヘッダーが翻訳単位の最小限のパブリックインターフェイスを表す.c / .hレイアウトが使用されてきました。同様に、.cpp / hpp。

それはほとんど正しいです。C ++クラスヘッダーには、最小限のパブリックインターフェイス以外のものが含まれることがよくあります。通常、プライベートなものも多く含まれています。これを軽減するために、PIMPLイディオムのようなものが使用されます。これは、ヘッダーのみのライブラリの「反対」のようなもので、必要なヘッダーコンテンツを最小限に抑えようとします。

しかし、あなたの主な質問に答えるために:これはトレードオフです。ヘッダーファイルに追加するライブラリコードが多いほど、コンパイラーはコードの速度を最適化する機会が多くなります(これが実際に発生する場合、または増加が顕著である場合は、まったく別の質問です)。一方、ヘッダー内のコードが多すぎると、コンパイル時間が長くなります。特に大規模なC ++プロジェクトでは、これは深刻な問題になる可能性があります。JohnLakosの「Large Scale C ++ Software Design」を参照してくださいソリューションはまだ有効です。

特に、安定した(サードパーティの)ライブラリを使用していないが、プロジェクト中に独自のライブラリを開発している場合、コンパイル時間が明らかになります。libで何かを変更するたびに、ヘッダーファイルを変更する必要があります。これにより、すべての依存ユニットの再コンパイルとリンケージが発生します。

私見では、ヘッダーのみのライブラリの人気は、テンプレートメタプログラミングの人気が原因です。ほとんどのコンパイラでは、型パラメータが提供されている場合にのみコンパイラがメインコンパイルプロセスを開始できるため、テンプレート化されたライブラリヘッダーのみである必要があります。パラメータ値。そのため、そのようなライブラリの「プリコンパイル済み」コンパイル単位を作成することは不可能(または少なくとも困難)になります。


6
要するに、ヘッダーのみのライブラリは効率的というよりも便利です。また、C ++には標準のパッケージマネージャーがないため、導入の促進に役立ちます。
マチューM.

6
@MatthieuM:いいえ、コンパイルされたコードは実際により効率的である場合があり、テンプレートライブラリの場合、ヘッダーのみの設計は通常、利便性の問題ではありません。そして、コンパイル時間の増加は間違いなく便利ではありません。
Doc Brown

ヘッダーにホットコードを含めると、実際にはより効率的なコンパイルコードが得られる場合がありますが、ヘッダーにすべてのコードを含める必要はないため、ヘッダーのみのライブラリから独立しています。
マチューM.

1
@MatthieuM .:それは確かに正しい、それにもかかわらず、私は「より便利な」という用語はケースをうまく説明していないと思う。
Doc Brown

3
私は以前の雇用主のためにスリム化された古いOSの上で大規模な組み込みプロジェクトに取り組みました。その場合、長いコンパイル時間の痛みを証明できます。ヘッダーファイルに詰め込みすぎた人は、容赦なく扱われます。
フレッドトムセン

15

さて、最初にあなたの仮定のいくつかを破壊しましょう:

  1. C ++のヘッダー専用ライブラリの利点の1つは、個別にコンパイルする必要がないことです。

個別にコンパイルすると、一部のみが変更された場合にすべてを再コンパイルする必要がない可能性があります。
したがって、アドバンテージではなくデメリット。

  1. CおよびC ++では、関数がヘッダーファイルで定義されている場合にのみインラインが意味を持ちます*。

はい、inline残っている唯一の効果はone-definition-ruleの例外です。
ただし、これらの定義が何らかの形で異なっている場合は、あなたに災いがあります。

したがって、関数がコンパイル単位の内部にある場合は、マークしstaticます。また、関数はインライン化するために使用可能である必要があるため、インライン化の可能性が高くなります。
それでも、少なくともMSVC ++、gcc、clangでサポートされているリンク時最適化を見てください。

  1. 従来、Cでは、ヘッダーが翻訳単位の最小限のパブリックインターフェイスを表す.c / .hレイアウトが使用されてきました。同様に、.cpp / hpp。

APIとABIの安定性を高め、コンパイル時間を最小限に抑えることは、最小限のインターフェイスのみを提示することです。

特に、C ++クラスは、プライベートビットがすべてヘッダーにリークするので、保護されたものが派生するかどうかに関係なく、C ++クラスは実際にはそれに適合していません。

設計パターンPIMPLは、このような詳細を削減するためのものです。

ただし、C ++でインターフェイスと実装を完全に分離できない部分はテンプレートです。
委員会は、エクスポートされたテンプレートを使用して何かを実行しようとしましたが、それはあまりにも複雑で実際には機能していないため放棄されました。

現在、彼らは適切なモジュールシステムに取り組んでいますが、ゆっくりしています。これにより、コンパイル時間が大幅に短縮されます。また、表面を縮小することでAPIとABIの安定性も向上します。

一般に、ヘッダーのみのライブラリは、従来のレイアウトよりもコードおよび実行時間の面で効率的ですか?もしそうなら、これは広範なインライン展開または他の最適化のためですか?

ヘッダーのみのライブラリは、コードサイズと実行時間でより効率的になりますが、それはライブラリが共有されるかどうか、ライブラリの使用量、使用方法、インライン化がその特定のケースで決定的な勝利を証明するかどうかによって異なります。

また、インライン化が最適化にとって非常に重要である理由は、インライン化自体が非常に大きな後押しであるためではありませんが、一定の伝播とさらなる最適化の機会のために開きます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.