[ACCEPTED]-Clean up your #include statements?-header

Accepted answer
Score: 24

To verify that header files are including 51 everything they need, I would creating a 50 source file that all it does is include 49 a header file and try to compile it. If 48 the compile fails, then the header file 47 itself is missing an include.

You get the 46 same effect by making the following rule: that 45 the first header file which foo.c or foo.cpp must 44 include should be the correspondingly-named 43 foo.h. Doing this ensures that foo.h includes 42 whatever it needs to compile.

Furthermore, Lakos' book 41 Large-Scale C++ Software Design (for example) lists many, many techniques 40 for moving implementation details out of 39 a header and into the corresponding CPP 38 file. If you take that to its extreme, using 37 techniques like Cheshire Cat (which hides 36 all implementation details) and Factory 35 (which hides the existence of subclasses) then 34 many headers would be able to stand alone 33 without including other headers, and instead 32 make do with just forward declaration to 31 opaque types instead ... except perhaps 30 for template classes.

In the end, each header 29 file might need to include:

  • No header files 28 for types which are data members (instead, data 27 members are defined/hidden in the CPP file 26 using the "cheshire cat" a.k.a. "pimpl" technique)

  • No 25 header files for types which are parameters 24 to or return types from methods (instead, these 23 are predefined types like int; or, if they're 22 user-defined types, then they're references 21 in which case a forward-declared, opaque 20 type declaration like merely class Foo; instead of 19 #include "foo.h" in the header file is sufficient).

What 18 you need then is the header file for:

  • The 17 superclass, if this is a subclass

  • Possibly 16 any templated types which are used as method 15 parameters and/or return types: apparently 14 you're supposed to be able to forward-declare 13 template classes too, but some compiler 12 implementations may have a problem with 11 that (though you could also encapsulate 10 any templates e.g. List<X> as implementation details 9 of a user-defined type e.g. ListX).

In practice, I 8 might make a "standard.h" which includes 7 all the system files (e.g. STL headers, O/S-specific 6 types and/or any #defines, etc) that are used by 5 any/all header files in the project, and 4 include that as the first header in every 3 application header file (and tell the compiler 2 to treat this "standard.h" as the 'precompiled 1 header file').


//contents of foo.h
#ifndef INC_FOO_H //or #pragma once
#define INC_FOO_H

#include "standard.h"
class Foo
{
public: //methods
  ... Foo-specific methods here ...
private: //data
  struct Impl;
  Impl* m_impl;
};
#endif//INC_FOO_H

//contents of foo.cpp
#include "foo.h"
#include "bar.h"
Foo::Foo()
{
  m_impl = new Impl();
}
struct Foo::Impl
{
  Bar m_bar;
  ... etc ...
};
... etc ...
Score: 11

I have the habit of ordering my includes 10 from high abstraction level to low abstraction 9 level. This requires that headers have to 8 be self-sufficient and hidden dependencies 7 are quickly revealed as compiler errors.

For 6 example a class 'Tetris' has a Tetris.h 5 and Tetris.cpp file. The include order for 4 Tetris.cpp would be

#include "Tetris.h"     // corresponding header first
#include "Block.h"      // ..then application level includes
#include "Utils/Grid.h" // ..then library dependencies
#include <vector>       // ..then stl
#include <windows.h>    // ..then system includes

And now I realize this 3 doesn't really answer your question since 2 this system does not really help to clean 1 up unneeded includes. Ah well..

Score: 7

Depending on the size of your project, looking 2 at the include graphs created by doxygen (with 1 the INCLUDE_GRAPH option on ) can be helpful.

Score: 6

Detecting superfluous includes has already 8 been discussed in this question.

I'm not aware of any 7 tools to help detect insufficient-but-happens-to-work 6 includes, but good coding conventions can 5 help here. For example, the Google C++ Style Guide mandates the 4 following, with the goal of reducing hidden 3 dependencies:

In dir/foo.cc, whose main purpose is 2 to implement or test the stuff in dir2/foo2.h, order 1 your includes as follows:

  1. dir2/foo2.h (preferred location — see details below).
  2. C system files.
  3. C++ system files.
  4. Other libraries' .h files.
  5. Your project's .h files.
Score: 5

One big problem with the remove a header 16 and recompile technique is that it can lead 15 to still-compiling, but wrong or inefficient 14 code.

  1. Template specialization: If you have 13 a template specialization for a specific 12 type that is in one header and the more 11 general template in another, removing the 10 specialization may leave the code in a compilable 9 state, but with undesired results.

  2. Overload 8 resolution: A similar issue - if you have 7 two overloads of one function in different 6 headers, but that take somewhat compatible 5 types, you can end up removing the version 4 that is the better fit in one case, but 3 still have the code compile. This is probably 2 less likely than the template specialization 1 version, but it is possible.

Score: 2

I've been thinking about writing something 28 that compiles each non-header file individually 27 many times, each time removing an #include statement. Continue 26 doing this until a minimal set of includes 25 is achieved.

I think this is misguided, and 24 will lead to "insufficient but just happens 23 to work" include sets.

Suppose your source 22 file uses numeric_limits, but also includes some header 21 file, that for reasons of its own includes 20 <limits>. That doesn't mean that your source file 19 shouldn't include <limits>. That other header file 18 probably isn't documented to define everything 17 defined in <limits>, it just so happens to do so. Some 16 day it might stop: maybe it only uses one 15 value as a default parameter of some function, and 14 maybe that default value changes from std::numeric_limits<T>::min() to 13 0. And now your source file doesn't compile 12 any more, and the maintainer of that header 11 file didn't even know that your file existed 10 until it broke his build.

Unless you have 9 crippling build problems right this minute, I 8 think the best way to remove redundant includes 7 is just to get into the habit of looking 6 over the list whenever you touch a file 5 for maintenance. If you find that you have 4 dozens of includes, and having reviewed 3 the file you still can't figure out what 2 each one is for, consider breaking down 1 into smaller files.

Score: 2

If you use Visual Studio compiler, you can 6 try /showIncludes compiler option and then 5 parse what it emits to stderr. MSDN: "Causes 4 the compiler to output a list of the include 3 files. Nested include files are also displayed 2 (files that are included from the files 1 that you include)."

Score: 1

Yup. We have a preprocessor of our own which 5 gives us access to our own macro language. It 4 also checks that header files are only included 3 one time. Creating a simple preprocessor 2 checking for multiple includes should be 1 fairly easy.

Score: 1

As far as tools go, I've used Imagix (this 4 was about 6 years ago) on windows to identify 3 includes that are unneeded as well as includes 2 which are needed but are indirectly included 1 thru another include.

Score: 1

Take a look at the cppclean project. Though they 17 haven't implemented that feature yet, but 16 it's planned to be done.

From the project 15 site:

CppClean attempts to find problems 14 in C++ source that slow development particularly 13 in large code bases. It is similar to lint; however, CppClean 12 focuses on finding global inter-module problems 11 rather than local problems similar to 10 other static analysis tools.

The goal is 9 to find problems that slow development in 8 large code bases that are modified over 7 time leaving unused code. This code can 6 come in many forms from unused functions, methods, data 5 members, types, etc to unnecessary #include 4 directives. Unnecessary #includes can cause considerable 3 extra compiles increasing the edit-compile-run 2 cycle.

And particularly on the #include feature:

  • (planned) Find unnecessary header files #included
    • No direct reference to anything in the header
    • Header is unnecessary if classes were forward declared instead
  • (planned) Source files that reference headers not directly #included, ie, files that rely on a transitive #include from another header

Here you 1 can find a mirror at BitBucket.

Score: 0

If you are coding in Eclipse with CDT, you 3 can use Organize Includes command. Just 2 hit Ctrl+Shift+O and it will add the necessary 1 includes and remove the unneeded ones.

More Related questions