Home / ぼやきごと / 2012-03-10
2012-03-10

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

libA、libBの2つの内作ライブラリを用いるappSampleというアプリケーションをC++で作成するものとします。

  • appSampleはlibA、libBに依存します。
  • libBはlibAに依存します。

そしてappSampleのソースファイル "App.cpp" が次のヘッダファイルをインクルードするものとします。

  1. appSampleのヘッダファイル。
  2. libBの公開ヘッダファイル。
  3. libAの公開ヘッダファイル。
  4. boost等、利用している外作ライブラリのヘッダファイル。
  5. C/C++標準や実装環境標準のヘッダファイル。

このとき、 #include の記述順序をどうしますか?

「気にしたことがない」という場合を除き、概ね次のどちらかになるのではないかと思います。*1

【X】1→2→3→4→5の順
すべて開くすべて閉じる
  1
  2
  3
  4
  5
  6
 
 
 
 
 
 
#include "App.h"
#include "libB/xxx.h"
#include "libA/yyy.h"
#include <boost/scoped_ptr.hpp>
#include <windows.h>
#include <iostream>
【Y】5→4→3→2→1の順
すべて開くすべて閉じる
  1
  2
  3
  4
  5
  6
 
 
 
 
 
 
#include <iostream>
#include <windows.h>
#include <boost/scoped_ptr.hpp>
#include "libA/yyy.h"
#include "libB/xxx.h"
#include "App.h"

依存関係の末端から先にインクルードするのが【X】、根元から先にインクルードするのが【Y】です。
このどちらがより良いインクルード順序であると考えられるでしょうか?

私は【X】を推します。
理由としては、例えば上のコード例における "libB/xxx.h" が次のような内容になっている場合があるからです。

すべて開くすべて閉じる
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 
 
 
 
-
|
-
|
|
-
!
!
|
|
#ifndef LIBB_XXX_H
#define LIBB_XXX_H
 
namespace libB
{
    class xxx
    {
    private:
        HANDLE _handle;
        // …中略…
    };
}
 
#endif // LIBB_XXX_H

このヘッダファイルだけ見れば「HANDLE 型を使っているのに "windows.h" をインクルードしてないとかアホか!」と思うことでしょう。
しかし、開発が大規模になり依存関係が増えてくると、こういったヘッダファイルの記述忘れは往々にして起こりえます。

このとき【Y】のインクルード順序だと、 "libB/xxx.h" よりも先に "windows.h" がインクルードされているため、問題なくコンパイルが通ってしまいます。
"libB/xxx.h" の記述ミスは、 "libB/xxx.h" が他の「"windows.h" をインクルードしていないソースコード」でインクルードされるまで気付かれません。
libBをappSampleの実装のみに用いているうちはそれでもいいかもしれませんが、将来的に他の実装で用いることになった場合に余計な手間が発生するリスクがあります。

もっとも【X】のインクルード順序であっても、例えば "App.h" に #include <windows.h> が記述されていた場合は同じ問題が起こりえます。
なので【X】も完璧であるとは言えません…が、少なくとも【Y】よりは記述忘れの早期発見確率は高くなるはずです。
特にC++であれば普通は "libB/xxx.h" で宣言されたクラス(構造体)の実装を記述する "xxx.cpp" を用意するはずなので、そこで【X】のインクルード順序を採っていればまず間違いなく気付くことができます。

以上から、ヘッダファイルのインクルードは依存関係の末端に近いものほど先に行うことを私は推奨します。

Category: [プログラミング][C++] - 2012-03-10 13:46:15

*1 もしかすると大多数の人は「気にしたことがない」に当てはまるのかもしれませんが。