Visual Studio で C/C++ インクルードをクリーンアップする
Visual Studio 17.8 プレビュー 1 以降の Visual Studio には、次の方法でコードの品質を向上させる #include
クリーンアップ機能が用意されています。
- 必要なヘッダー ファイルが別のヘッダー ファイルによって間接的に含まれている理由でのみコンパイルされるコードのヘッダー ファイルを追加するオファー。
- 未使用のヘッダー ファイルを削除するためのオファーでは、ビルド時間とコードの清潔さが向上します。
[クリーンアップを含める] は、既定ではオンになっています。 構成する方法については、「Visual Studio で C/C++ インクルード クリーンアップを構成する」を参照してください。
直接ヘッダーと間接ヘッダー
まずは、いくつかの用語について説明します。
- 直接ヘッダーは、コード内で明示的に
#include
を指定したヘッダーです。 - 間接ヘッダーは、明示的に
#include
に指定しないヘッダーです。 代わりに、直接含めるヘッダー ファイルがそれを含みます。 また、間接ヘッダーが含まれるtransitively
とも言います。
[クリーンアップを含める] でコードを分析し、使用されていないヘッダーと間接的に含まれるヘッダーを決定します。 次のヘッダー ファイルを考えてみましょう。
// myHeader.h
#include <string>
#include <iostream>
void myFunc()
{
std::string s = "myFunc()\n";
std::cout << s;
}
また、それを使用するプログラムは以下のとおりです。
// myProgram.cpp
#include "myHeader.h"
int main()
{
std::string s = "main()"; // string is indirectly included by myHeader.h
std::cout << s; // cout is indirectly included by myHeader.h
myFunc();
}
myHeader.h
は myProgram.cpp
に明示的に含まれているため、直接ヘッダーです。 myHeader.h
に <string>
と <iostream>
が含まれるため、間接ヘッダーです。
問題は、myProgram.cpp
が std::string
と std::cout
を使用しているものの、それらを定義するヘッダーは直接含まないことです。 このコードをコンパイルできたのは、myHeader.h
がこれらのヘッダーを含むためです。 myHeader.h
がいずれかを含まなくなったら、myProgram.cpp
はコンパイルできなくなるため、このコードは不安定になります。
C++ のガイドラインによると、ヘッダー ファイルの変更によってコードが不安定にならないように、依存するすべてのヘッダーを明示的に含めることをお勧めします。 詳細については、「C++ Core Guidelines SF.10」を参照してください。
[クリーンアップを含める] は、コードを分析して、未使用のヘッダーと間接的に含まれるヘッダーを識別します。 「Visual Studio の C++ #include ツールを構成する」に記載されている設定に基づいてフィードバックが提供されます。 フィードバックは、エラー一覧の警告、推奨事項などの形式で行われます。[クリーンアップを含める] によって提供されるフィードバックの詳細については、[クリーンアップを含める] メッセージを参照してください。
未使用のヘッダー
コードの進化に伴い、ヘッダー ファイルが不要になる可能性があります。 複雑なプロジェクトでは、これを追跡するのは困難です。 コンパイラが不要なヘッダー ファイルを処理するため、時間の経過とともにビルドに時間がかかる可能性があります。 [クリーンアップを含める] は、未使用のヘッダーを見つけて削除するのに役立ちます。 たとえば、myFunc()
が次の myProgram.cpp
でコメント アウトされた場合はどうですか。
// myProgram.cpp
#include "myHeader.h"
int main()
{
std::string s = "main()"; // string is indirectly included from myHeader.h
std::cout << s; // cout is indirectly included from myHeader.h
// myFunc(); // directly included from myHeader.h
}
次のスクリーンショットでは、#include "myHeader.h"
は myFunc()
がコメント アウトされて使用されていないため、淡色表示されています (Visual Studio の C++ #include ツールの構成に記載されている設定)。
淡色表示された #include
にカーソルを合わせると、クイック アクション メニューが表示されます。 電球をクリック (または [修正候補の表示] リンクを選択) すると、未使用のファイルに関連するアクションが表示されます。
推移的に使用されるヘッダーを追加する
未使用のヘッダー ファイルの削除を選択することもできますが、<string>
と <iostream>
が myheader.h
を介して間接的に含まれるため、コードが破損します。
代わりに、[推移的に使用されたすべてを追加し、未使用の #includes をすべて削除する] を選択できます。 これにより、未使用のヘッダー myHeader.h
が削除されますが、myHeader.h
を介して間接的に含まれる使用中のヘッダーも追加されます。 この場合の結果は、#include <string>
と #include <iostream>
が myProgram.cpp
に追加され、#include "myHeader.h"
が削除されます。
// myProgram.cpp
#include <iostream>
#include <string>
int main()
{
std::string s = "main()"; // string is directly included from <string>
std::cout << s; // cout is directly included from <string>
// MyFunc();
}
このツールではコメントは更新されませんが、現時点ではコードで std::string
と std::cout
が直接使用されていることがわかります。 このコードは、他の必要なヘッダーを含めるために myHeader.h
に依存しないため、不安定ではなくなります。
ベスト プラクティス
最初に間接的に含められたヘッダー ファイルを追加することなく、未使用と思われるヘッダー ファイルを削除しないでください。 その理由は、コードが未使用のヘッダー ファイルで間接的に含めることに依存する可能性があるためです。 推移的に使用されるヘッダーを最初に追加します。 その後、未使用のヘッダーを削除しても、削除したヘッダー ファイルによって間接的に含まれるヘッダー ファイルがないため、コンパイル エラーは発生しません。
これを行う方法の 1 つは、[不足しているインクルード候補レベルの追加] を [提案される解決策] に設定することです ([ツール]>[オプション]>[テキスト エディター]>[C/C++]>[コードのクリーンアップ])。 また、[未使用のインクルード候補レベルの削除] を [提案される解決策] に設定します。 次に、以下の操作を実行します。
- エラーの一覧で、フィルターが [Build + IntelliSense] に設定されていることを確認します。
- "#include x からのコンテンツがこのファイルで使用され、推移的に含まれている" のインスタンスを探します。
- 候補のある行にカーソルを合わせます。 電球ドロップダウンから、[推移的に使用されるすべてのインクルードを追加する] を選択します。
- 推移的なインクルードに関して提案されるすべての解決策に対処するまで、プロジェクトでこれらの手順を繰り返します。
- 未使用のインクルードを削除する: エラー一覧で、"#include x はこのファイルで使用されていません" のインスタンスを探します。
- 未使用のヘッダーにカーソルを合わせます。 電球ドロップダウンから、[未使用のインクルードをすべて削除する] を選択します。
- [クリーンアップを含める] の候補がすべて解決されるまで、プロジェクトでこれらの手順を繰り返します。
この簡単な概要では、[クリーンアップを含める] を使用して未使用のヘッダーを削除し、間接的に含まれていたヘッダーを追加する方法について説明しました。 これにより、コードをクリーンに維持し、より迅速にビルドし、コードの不安定性を軽減するのに役立ちます。
関連項目
Visual Studio で C/C++ インクルード クリーンアップを構成する
インクルード クリーンアップのメッセージ