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

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


当前回答

还可以查看include-what-you-use,它可以解决类似的问题。

其他回答

CLion是JetBrains开发的C/ c++ IDE,可以即时检测冗余内容。这些在编辑器中是灰色的,但也有一些函数可以优化当前文件或整个项目中的包含。

我发现你需要为这个功能付费;当第一次加载时,CLion需要一段时间来扫描和分析您的项目。

如果您正在使用Eclipse CDT,您可以尝试http://includator.com,它对beta测试人员是免费的(在撰写本文时),并自动删除多余的#includes或添加缺失的#includes。对于那些拥有FlexeLint或PC-Lint并正在使用Elicpse CDT的用户,http://linticator.com可能是一个选项(beta测试也是免费的)。虽然它使用了Lint的分析,但它提供了自动删除多余的#include语句的快速修复。

The problem with detecting superfluous includes is that it can't be just a type dependency checker. A superfluous include is a file which provides nothing of value to the compilation and does not alter another item which other files depend. There are many ways a header file can alter a compile, say by defining a constant, redefining and/or deleting a used macro, adding a namespace which alters the lookup of a name some way down the line. In order to detect items like the namespace you need much more than a preprocessor, you in fact almost need a full compiler.

Lint更多的是一个样式检查器,当然不会有这个完整的功能。

我想你会发现检测多余include的唯一方法是删除、编译和运行套件。

您可以编写一个快速脚本,删除单个#include指令,编译项目,并在没有发生编译错误的情况下记录#include中的名称和它被删除的文件。

让它在晚上运行,第二天你就会有一个100%正确的可以删除的包含文件列表。

有时候蛮力很管用:-)


编辑:有时它不会:-)。下面是一些来自评论的信息:

Sometimes you can remove two header files separately, but not both together. A solution is to remove the header files during the run and not bring them back. This will find a list of files you can safely remove, although there might a solution with more files to remove which this algorithm won't find. (it's a greedy search over the space of include files to remove. It will only find a local maximum) There may be subtle changes in behavior if you have some macros redefined differently depending on some #ifdefs. I think these are very rare cases, and the Unit Tests which are part of the build should catch these changes.

我尝试过使用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文件首先包含它自己的头文件。(剪) 头文件必须包含解析它所需的所有头文件。(剪) 头文件应该有最少的头文件来解析它。(剪)