我经常发现文件的头部分总是变得越来越大,但它从来没有变小过。在源文件的整个生命周期中,类可能会被移动和重构,并且很可能有相当多的#include不需要存在。保留它们只会延长编译时间,并增加不必要的编译依赖关系。试图找出哪些仍然需要是相当乏味的。

是否有某种工具可以检测多余的#include指令,并建议哪些我可以安全地删除? 棉绒会这样吗?


当前回答

我尝试过使用Flexelint (PC-Lint的unix版本),结果有些复杂。这可能是因为我正在处理一个非常庞大且复杂的代码库。我建议仔细检查报告为未使用的每个文件。

主要的担忧是假阳性。同一报头的多个包含被报告为不需要的报头。这是很糟糕的,因为Flexelint没有告诉你头文件被包含在哪一行或者它之前被包含在哪里。

自动化工具可能会出错的一种方式是:

在A.hpp:

class A { 
  // ...
};

在B.hpp:

#include "A.hpp

class B {
    public:
        A foo;
};

在C.cpp:

#include "C.hpp"  

#include "B.hpp"  // <-- Unneeded, but lint reports it as needed
#include "A.hpp"  // <-- Needed, but lint reports it as unneeded

如果你盲目地跟随Flexelint的消息,你会把#include依赖项搞砸。有更多的病理情况,但基本上你需要自己检查标题,以获得最好的结果。

我强烈推荐这篇来自博客Games的关于物理结构和c++的文章。他们推荐了一个全面的方法来清理#include混乱:

的指导方针 以下是从Lakos的书中提炼出来的一组指导原则,可以最大限度地减少文件之间的物理依赖关系。我已经使用它们很多年了,我对效果一直很满意。 每个cpp文件首先包含它自己的头文件。(剪) 头文件必须包含解析它所需的所有头文件。(剪) 头文件应该有最少的头文件来解析它。(剪)

其他回答

有一个免费的工具包括文件依赖监视器,它可以集成到可视化工作室中。它用红色显示多余的#include。

Clangd现在正在为你做这件事。clang-tidy可能很快也能做到这一点。

CScout重构浏览器可以检测C(不幸的是不是c++)代码中多余的include指令。你可以在这篇期刊文章中找到它如何工作的描述。

本文解释了一种使用Doxygen解析来删除#include的技术。这只是一个perl脚本,所以它很容易使用。

结束这个讨论:c++预处理器是图灵完成的。包含是否是多余的,这是一个语义属性。因此,由Rice定理可知,包含是否多余是不可判定的。不可能有一个程序(总是正确地)检测包含是否多余。