C / C ++インクルードヘッダーファイルの順序


287

どのような順序でファイルを指定する必要がありますか。つまり、あるヘッダーを別のヘッダーの前に含める理由は何ですか。

たとえば、システムファイル、STL、およびBoostはローカルインクルードファイルの前または後にありますか?


2
また、Java開発者が個別のヘッダーを使用しないことを決定したのは、以下の多数の回答です。:-)ただし、いくつかの本当に良い答えがあります。特に、独自のヘッダーファイルを単独で使用できるようにするための警告です。
Chris K

37
100票以上の投票があり、かなりの人にとって明らかに興味深い質問が「建設的ではない」としてクローズされるのが好きです。
Andreas

強くお勧めの記事
Kalsan

3
@ mrt、SOはスープナチコミュニティを強く思い出させます。非常に厳しい規則に従うか、「適切な回答/コメントがない!」のいずれかです。誰かがプログラムにどのような方法で関連の問題がある場合はそれにもかかわらず、これは(通常は)行くための最初のサイト..です
イマーゴ

回答:


289

コンパイルされる限り、推奨される順序はないと思います!厄介なのは、一部のヘッダーで最初に他のヘッダーを含める必要がある場合です...これは、インクルードの順序ではなく、ヘッダー自体の問題です。

私の個人的な好みは、各サブセクションをアルファベット順にローカルからグローバルに移動することです。

  1. このcppファイルに対応するhファイル(該当する場合)
  2. 同じコンポーネントのヘッダー
  3. 他のコンポーネントのヘッダー
  4. システムヘッダー。

1.の私の理論的根拠は、各ヘッダー(cppがある)が#include前提条件なしで終了できることを証明する必要があるということです(末端技術:ヘッダーは「自己完結型」)。そして、残りはそこから論理的に流れるようです。


16
グローバルからローカルに移行することと、ソースファイルに対応するヘッダーが特別な扱いを受けないことを除いて、あなたとほとんど同じです。
ジョンパーディ

127
@ジョン:私はそれはかなり反対だと思います!:-)私はあなたのメソッドが隠された依存関係を導入する可能性があると主張します。たとえば、myclass.cppに<string>、次に<myclass.h>が含まれている場合、ビルド時にmyclass.h自体が文字列に依存する可能性があることをキャッチする方法はありません。したがって、後であなたまたは他の誰かがmyclass.hをインクルードしても、文字列は必要ない場合、cppまたはヘッダー自体のいずれかで修正する必要があるエラーが発生します。でも、それが長期的に見てうまくいくと人々が考えていることかどうか知りたいです。あなたの提案に回答を投稿して、誰が「勝者」になるか見てみましょう。;-)
10

3
一般的な注文に固有のものは、Dave Abrahamsの推奨事項から現時点で使用するものです。そして、ローカルからより一般的なものまで、ソースに含まれるヘッダー欠落を明らかにする@squelartと同じ理由を指摘します。重要なのは、サードパーティやシステムライブラリよりも、間違いを犯しやすいということです。
GrafikRobot、

7
@PaulJansenこれは悪い習慣であり、それを爆破する可能性が高い手法を使用して、隠れた状態にする代わりに悪い習慣を修正できるようにするとよいでしょう。ローカルからグローバルFTW
bames53

10
@PaulJansenはい、私は標準的な行動を覆すことに言及していました。たとえば、ODRの破壊が偶然に発生する可能性があるのと同様に、それは偶然に発生する可能性があります。解決策は、そのような事故が発生したときに非表示になるプラクティスを使用するのではなく、間違いをできるだけ早期に発見して修正できるように、それらをできるだけ大きく吹き飛ばす可能性が最も高いプラクティスを使用することです。
bames53 2013年

106

心に留めておくべき重要なことは、ヘッダーが最初に含まれている他のヘッダーに依存するべきではないということです。これを保証する1つの方法は、他のヘッダーの前にヘッダーを含めることです。

「Thinking in C ++」では、Lakosの「Large Scale C ++ Software Design」を参照して、これについて特に言及しています。

外部から提供された宣言や定義なしで、コンポーネントの.hファイル自体が確実に解析されるようにすることで、潜在的な使用エラーを回避できます... .cファイルの最初の行に.hファイルを含めることで、重要な部分がないコンポーネントの物理インターフェイスに固有の情報の一部が.hファイルにありません(または、ある場合は、.cファイルをコンパイルしようとするとすぐにわかります)。

つまり、次の順序で含めます。

  1. この実装のプロトタイプ/インターフェースヘッダー(つまり、この.cpp / .ccファイルに対応する.h / .hhファイル)。
  2. 必要に応じて、同じプロジェクトの他のヘッダー。
  3. 他の非標準、非システムライブラリ(たとえば、Qt、Eigenなど)のヘッダー。
  4. 他の「ほぼ標準」のライブラリ(Boostなど)のヘッダー
  5. 標準のC ++ヘッダー(たとえば、iostream、functionなど)
  6. 標準のCヘッダー(cstdint、dirent.hなど)

この順序に含まれることに問題があるヘッダーがある場合は、それらを修正するか(使用している場合)、使用しないでください。きれいなヘッダーを書かないボイコットライブラリ。

GoogleのC ++スタイルガイドほぼ逆のことを主張しており、まったく正当化されていません。私は個人的にラコスのアプローチを好む傾向があります。


13
現在のところ、Google C ++スタイルガイドでは、Lakosの提案に従って、関連するヘッダーファイルを最初に含めることを推奨しています。
FilipBártek2016年

プロジェクト内のヘッダーのインクルードを開始すると、システムの多くの依存関係を取り込むため、最初の関連ヘッダーを超えることはありません。
ミカ

@Micah-「システムの多くの依存関係」を引き込むプロジェクト内ヘッダーは設計が良くないため、ここで回避しようとしています。ポイントは、不要なインクルードと未解決の依存関係の両方を回避することです。最初に他のヘッダーを含めなくても、すべてのヘッダーを含めることができるはずです。プロジェクト内のヘッダーにシステムの依存関係が必要な場合は、そのようにしてください。そのファイルのローカルコードがシステムの依存関係を使用しない限り、その後にシステムの依存関係を含めないでください(含めるべきではありません)。使用するシステムdepを含めるために、ヘッダー(自分のものも含む)に依存することはできません。
Nathan Paul Simons

49

私は、大多数の問題を回避する2つの単純なルールに従います。

  1. すべてのヘッダー(そして実際に任意のソースファイル)は、彼らが必要とするものを含むべきです。彼らは物事を含め、ユーザーに依存すべきではありません
  2. 付属物として、すべてのヘッダーにはガードが含まれている必要があります。これにより、上記のルール1の野心的な適用によってヘッダーが複数回含まれることがなくなります。

私は以下のガイドラインにも従います:

  1. 最初にシステムヘッダー(stdio.hなど)を分割線に含めます。
  2. それらを論理的にグループ化します。

言い換えると:

#include <stdio.h>
#include <string.h>

#include "btree.h"
#include "collect_hash.h"
#include "collect_arraylist.h"
#include "globals.h"

ガイドラインですが、それは主観的なことです。一方、私は厳格に施行し、不快なサードパーティの開発者が私のビジョンにサブスクライブしない場合は、インクルードガードとグループ化されたインクルードを使用して「ラッパー」ヘッダーファイルを提供するところまで行っています:-)


6
+1「すべてのヘッダー(および実際にはすべてのソースファイル)には、必要なものが含まれている必要があります。ヘッダーを含め、ユーザーに依存すべきではありません。」しかし、非常に多くの人々が、たとえばNULLを使用してこの暗黙の包含動作に依存し、<cstddef>を含めません。このコードを移植しようとすると、NULLでコンパイルエラーが発生するので非常に煩わしいです(私が今すぐ0を使用している理由の1つ)。
stinky472

20
なぜ最初にシステムヘッダーを含めるのですか?それはあなたの最初のルールのために周りの理由が他の方が良いでしょう。
jhasse

機能テストマクロを使用する場合、最初のインクルードは標準ライブラリヘッダーではないはずです。したがって、一般的に言えば、「最初にローカル、次にグローバル」というポリシーが最適です。
hmijailは、2017

1
「ユーザーに依存しない」という最初の提案について、ヘッダーファイルをインクルードする必要がないヘッダーファイル内のフォワード宣言はどうですか?フォワード宣言は適切なファイルを含めるためにヘッダーファイルのユーザーに負担をかけるので、ヘッダーファイルを含める必要があります。
ゾソ2017年

22

自分のレンガを壁に追加します。

  1. 各ヘッダーは自己完結型である必要があり、少なくとも1回は最初に含まれている場合にのみテストできます
  2. シンボル(マクロ、型など)を導入して、サードパーティのヘッダーの意味を誤って変更してはなりません。

だから私は通常このように行きます:

// myproject/src/example.cpp
#include "myproject/example.h"

#include <algorithm>
#include <set>
#include <vector>

#include <3rdparty/foo.h>
#include <3rdparty/bar.h>

#include "myproject/another.h"
#include "myproject/specific/bla.h"

#include "detail/impl.h"

次のグループから空白行で区切られた各グループ:

  • 最初にこのcppファイルに対応するヘッダー(健全性チェック)
  • システムヘッダー
  • 依存関係の順序で整理されたサードパーティのヘッダー
  • プロジェクトヘッダー
  • プロジェクトのプライベートヘッダー

また、システムヘッダーとは別に、各ファイルは名前空間の名前が付いたフォルダーにあります。これは、この方法で追跡しやすいためです。


2
他のヘッダファイルがそれらに影響されないように。これらのシステムヘッダーが定義する内容(XインクルードとWindowsインクルードの両方が#define他のコードをめちゃくちゃにすることについて悪いこと)と暗黙の依存関係を防ぐことの両方によって。たとえば、コードベースのヘッダーファイルがfoo.h実際に依存し<map>ているが、.ccファイルで使用されているすべての場所で、<map>既にインクルードされている場合、おそらく気付かないでしょう。foo.h最初に含めずに誰かが含めようとするまで<map>。そして、彼らはイライラするでしょう。

@ 0A0D:2番目の問題は、ここでの順序の問題ではありません。これは、それぞれに最初にそれを含む.h少なくとも1つの問題があるためです.cpp(実際、私の個人コードでは、ユニットテストに関連付けられたものが最初に含まれ、ソースコードはそれを正当なグループに含めます)。影響を受けないことに関して、いずれかのヘッダーに含まれている<map>場合、その後に含まれるすべてのヘッダーが影響を受けるため、私にとっては負けた戦いのようです。
Matthieu M.

1
もちろん、ビルド時間を長くするだけなので不要なインクルードを必要とする古いコード(またはさらに新しいコード)を定期的に回避して修正するのはそのためです。

@MatthieuM。つまり、1つ目のポイントの背後にある根拠を知りたいのHeader corresponding to this cpp file first (sanity check)です。#include "myproject/example.h"すべてのインクルードの最後に移動した場合、特に何かありますか?
MNS 2016

1
@MNS:ヘッダーは独立している必要があります。つまり、ヘッダーの前に他のヘッダーを含める必要はありません。これを確認するのはヘッダーの作成者としてのあなたの責任であり、そのための最善の方法は、このヘッダーが最初に含まれる1つのソースファイルを用意することです。ヘッダーファイルに対応するソースファイルを使用するのは簡単です。別の適切な選択は、ヘッダーファイルに対応する単体テストのソースファイルを使用することですが、汎用性は低くなります(単体テストがない場合があります)。
Matthieu M.

16

私はお勧め:

  1. 作成している.ccモジュールのヘッダー。(プロジェクト内の各ヘッダーがプロジェクト内の他のヘッダーに暗黙的に依存しないようにするのに役立ちます。)
  2. Cシステムファイル。
  3. C ++システムファイル。
  4. プラットフォーム/ OS /その他のヘッダーファイル(例:win32、gtk、openGL)。
  5. プロジェクトの他のヘッダーファイル。

そしてもちろん、可能な場合、各セクション内のアルファベット順。

#includeヘッダーファイルで不要なを回避するために、常に前方宣言を使用してください。


+1、でもなぜアルファベット順?気分が良くなるようなもののようですが、実用的なメリットはありません。
ベン

9
アルファベット順は任意の順序ですが、簡単です。アルファベット順にする必要はありませんが、すべての人が一貫してそれを行うように、いくつかの順序を選択する必要があります。重複を回避し、マージを容易にすることがわかりました。崇高なテキストを使用する場合、F5がそれらを注文します。
i_am_jorf 14

14

これは正気の世界のどこでも推奨される方法ではないと確信していますが、同じシステム内で字句的にソートされたファイル名の長さでシステムインクルードを並べるのが好きです。そのようです:

#include <set>
#include <vector>
#include <algorithm>
#include <functional>

include-order依存関係の恥を避けるために、他の人々の前に独自のヘッダーを含めることは良い考えだと思います。


3
私は、2番目、3番目、最初の文字の順に構成されるキーを使用してヘッダーを並べ替えるのが好きです:-)したがって、例として、ベクトル、セット、アルゴリズム、関数を使用します。
paxdiablo

@paxdiablo、ヒントをありがとう。使用を検討していますが、ファイル名の山が不安定になり、転倒する可能性があるのではないかと心配しています。おそらく-誰がこの問題が発生した場合に含まれている場合があります知っていますwindows.h
clstrfsck 2010年

40
長さで並べ替え?狂気!
James McNellis、

1
最初は+1。実際には、ファイル内のヘッダーを目で確認する必要がある場合は、アルファベット順よりもはるかに優れています。
Kugel

6

これは主観的ではありません。ヘッダーが#include特定の順序であることに依存していないことを確認してください。STLまたはBoostヘッダーを含める順序は問題ではないことを確認できます。


1
私は暗黙の依存関係を想定していませんでした
Anycorn

はい、ただしコンパイラはこの仮定を行うことができないため、#include <A>、<B>は、コンパイルされるまで#include <B>、<A>と同じにはなりません。
ミハイル

4

最初に、.cpp ...に対応するヘッダーを含めます。つまり、他のものsource1.cppを含めるsource1.h前に含める必要があります。私が考えることができる唯一の例外は、プリコンパイル済みヘッダーでMSVCを使用する場合stdafx.hです。その場合、何よりも先に含める必要があります。

理由:source1.h他のファイルの前にbefore を含めることで、依存関係なしにスタンドアロンで動作できるようになります。source1.h後日、依存関係が発生した場合、コンパイラは、必要な転送宣言をに追加するよう直ちに警告しますsource1.h。これにより、依存関係者がヘッダーを任意の順序で含めることができます。

例:

source1.h

class Class1 {
    Class2 c2;    // a dependency which has not been forward declared
};

source1.cpp

#include "source1.h"    // now compiler will alert you saying that Class2 is undefined
                    // so you can forward declare Class2 within source1.h
...

MSVCユーザー:プリコンパイル済みヘッダーの使用を強くお勧めします。したがって、#include標準ヘッダー(および変更されない他のヘッダー)のすべてのディレクティブをに移動しstdafx.hます。


2

.cppに対応する.hppが存在する場合は、対応する.hppから始めて、最も具体的なものから最も具体的でないものまで含めます。このようにして、自己完結していないヘッダーファイル内の非表示の依存関係が明らかになります。

これは、事前にコンパイルされたヘッダーを使用することで複雑になります。これを回避する1つの方法は、プロジェクトをコンパイラ固有にせずに、プロジェクトヘッダーの1つをプリコンパイル済みヘッダーインクルードファイルとして使用することです。


1

これは、C / C ++の世界では難しい問題であり、標準を超える要素がたくさんあります。

ヘッダーファイルの順序は、squelartが言ったように、コンパイルされる限り、深刻な問題ではないと思います。

私の考えは次のとおりです。これらのすべてのヘッダーに記号の競合がない場合、どの順序でも問題ありません。ヘッダーの依存関係の問題は、欠陥のある.hに#include行を追加することで後で修正できます。

実際の面倒は、一部のヘッダーが(#if条件をチェックすることによって)その上にあるヘッダーに従ってアクションを変更するときに発生します。

たとえば、VS2005のstddef.hには、次のものが含まれます。

#ifdef  _WIN64
#define offsetof(s,m)   (size_t)( (ptrdiff_t)&(((s *)0)->m) )
#else
#define offsetof(s,m)   (size_t)&(((s *)0)->m)
#endif

ここで問題:カスタムヘッダー( "custom.h")がありoffsetof、システムヘッダーで提供されていない古いコンパイラーを含め、多くのコンパイラーで使用する必要がある場合は、ヘッダーに書き込む必要があります。

#ifndef offsetof
#define offsetof(s,m)   (size_t)&(((s *)0)->m)
#endif

そして、必ずすべてのシステムヘッダーの#include "custom.h" 後にユーザーに伝えるようにしてください。そうしないと、offsetofstddef.h の行がマクロ再定義エラーをアサートします。

今後は、このようなケースに遭遇しないようお祈り申し上げます。

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