清理 Visual Studio 中的 C/C++ include
从 Visual Studio 17.8 预览版 1 开始,Visual Studio 提供了一项 #include
清理功能,可通过以下方式提高代码的质量:
- 为编译目的只是由于其他头文件间接包含了所需头文件的代码,添加头文件。
- 移除未使用的头文件 - 提高编译时间和代码整洁度。
默认情况下,Include Cleanup 处于打开状态。 若要了解如何配置它,请参阅在 Visual Studio 中配置 C/C++ Include Cleanup。
直接标头与间接标头
首先,让我们了解一些术语:
- 直接标头是在代码中显式
#include
的标头。 - 间接标头是隐式
#include
的标头。 而直接包含的头文件会包含标头。 换言之,间接标头通过transitively
方式包含。
Include Cleanup 会分析代码并确定哪些标头未使用,以及哪些标头是间接包含的。 请考虑以下头文件:
// 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。
Include Cleanup 会对代码进行分析,以识别未使用和间接包含的标头。 它基于在 Visual Studio 中配置 C++ #include 工具中所述的设置提供反馈。 反馈可以采用错误列表警告、建议等形式。有关 Include Cleanup 提供的反馈的更多详细信息,请参阅 Include Cleanup 消息。
未使用的标头
随着代码的演变,你可能不再需要一些头文件。 这很难在复杂的项目中进行跟踪。 随着时间的推移,编译可能需要更长的时间,因为编译器将处理不必要的头文件。 Include Cleanup 可帮助你查找和移除未使用的标头。 例如,如果在 myProgram.cpp
中注释掉了 myFunc()
会怎样:
// 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"
呈灰显状态(在 Visual Studio 中配置 C++ #include 工具中对该设置进行了介绍),因为它在 myFunc()
被注释掉后将不再使用。
将光标悬停在灰显的 #include
上以显示快速操作菜单。 单击灯泡(或选择“显示潜在修复”链接),查看与未使用的文件相关的操作:
添加可传递使用的标头
我们可以选择移除未使用的头文件,但这会破坏代码,因为 <string>
和 <iostream>
是通过 myheader.h
间接包含的。
我们可以改为选择“添加所有可传递使用的 #include,并移除所有未使用的 #include”。 这会移除未使用的标头 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
来包含其他必需的标头。
最佳做法
在未首先添加间接包含的头文件的情况下,请勿移除看似未使用的头文件。 这是因为您的代码可能依赖于头文件中的间接 include,而该头文件在其他情况下是不使用的。 首先添加可传递使用的标头。 然后,在移除未使用的标头时,就不会因为缺少已移除的头文件间接包含的头文件而出现编译错误。
执行此操作的一种方法是将 Include Cleanup 中针对“添加缺失的 include 的建议级别”的设置设定为“建议”(“工具”>“选项”>“文本编辑器”>“C/C++”>“代码清理”)。 此外,还需要将“移除未使用的 include 的建议级别”设置为“建议”。 然后:
- 在错误列表中,确保筛选器设置为“编译 + IntelliSense”。
- 查找“此文件中使用了来自 #include x 的内容并可传递包含”的实例。
- 将光标悬停在带有建议的行上。 从灯泡下拉列表中,选择“添加所有可传递使用的 include”。
- 重复项目中的这些步骤,直到解决有关可传递 include 的所有建议。
- 移除未使用的 include:在错误列表中,查找“#include x 未在此文件中使用”的实例。
- 将光标悬停在未使用的标头上。 从灯泡下拉列表中,选择“移除所有未使用的 include”。
- 重复项目中的这些步骤,直到解决所有 Include Cleanup 建议。
在此简要概述中,你已了解 Include Cleanup 如何帮助移除未使用的标头及添加间接包含的标头。 这有助于保持代码整洁,可以提高编译速度,减少代码出错几率。
另请参阅
在 Visual Studio 中配置 C/C++ Include Cleanup
Include Cleanup 消息