I have already argued that you shouldn’t put all your includes in your .h files. Here is one more reason, compilation time.
Have a look at this example, where the arrows mean “includes”
file5.h apparently need access to something which is defined in
file4.h, which again needs access to three other headers. Because of this, all other files that include
file5.h also includes
#include "file.h" really means “copy the entire contents of
file.h here before compiling”. So in this example,
file[1-3] is copied into
file4.h, which is then copied into
file5.h, which again is copied into the three
cpp files. Every file takes a bit of time to compile, and now each
cpp file doesn’t only need to compile its own content, but also all of the (directly and indirectly) included headers. What happens if we add some compilation times to our diagram? The compilation time of the file itself is on the left, the compilation time including the included headers are on the right.
As we can see, this has a dramatic effect on compilation time.
file7.cpp just needed something from
file5.h, but got an entire tree of headers which added 1.2 seconds to their compilation times. This might not sound much, but those numbers add up when the number of files is large. Also, if you’re trying to do TDD, every second counts. And in some cases, compilation times of individual headers can be a lot worse than in this example.
file5 didn’t really need to have
#include "file4.h" in the header, but could move it to the source file instead? Then we would have this diagram:
The compilation time of
file[6-7].cpp is significantly reduced.
Now let’s look at what happens if a header file is modified. Let’s say you need to make a minor update in
file1.h. When that file is changed, all the files that include it need to be recompiled as well:
But if we were able to
#include "file4.h" in
file5.cpp instead of
file5.h, only one cpp file would need to recompile:
Recompilation time: 1.7 seconds vs. 4.5 seconds. And in a large project, this would be a lot worse. So please try to move your
#includes down into the cpp files whenever you can!
The Graphviz code and makefile for this blog post is available on GitHub.
If you enjoyed this post, you can subscribe to my blog, or follow me on Twitter.
9 thoughts on “Another Reason to Avoid #includes in Headers”
I completely understand your point, and I have advocated the same strategy many times. All of this was when I was writing firmware in C, sometimes on very large systems.
When some of our projects moved over to C++, with all sorts of inheritance hierarchies, classes, etc. I got into the habit of putting #Include “base.h” inside of derived.h. That way, when someone wants to use a “derived” object, they only need to include its header file. And certainly 100% of the time that you’re #including derived.h you’ll need base.h, so why not put it there?
Same thing goes for struct definitions, #defines, etc…
Also makes for slightly better maintainability, doesn’t it? Let’s say now that class “Derived” stands on its own, i.e. it no longer inherits from Base. Now with the approach described above I have to go into 100 .c files and remove “#include “base.h””, don’t I?
I don’t know, I am really of mixed feelings here. When I worked on huge, distributed telecom systems, I fought mightily to enforce “no header files included in other header files”. I really did. But now I’ve swung the other way & do it all the time. :-(
Not saying one approach is better or worse than the other, I’m just agreeing with you in spirit but not always following this in practice.
Thanks for your comment. I definitely agree with you, base.h always goes in derived.h, not in derived.cpp. The reason being that Derived cannot be compiled without the full definition of Base available.
So if derived.h doesn’t include base.h, all the files that include derived.h will also have to include base.h, and there is no point in avoiding the include any more.
In general, I think every header file should include all other headers needed for it to compile. (Except when using precompiled headers, but that’s another story.)
Seams to me like having to deal with this is wasting time. All other languages have moved to a single file. Two files equals twice the maintenance time. Isn’t this whole conversation just silly. The ONLY time you need a .h file is if your making a dynamic library. Why not just include the .cpp file with the definition and decoration and be done with it?
This is because of the separate compilation model of C++. Any cpp file has to be compilable on its own, and thus needs all declarations available. I agree that it’s a good thing newer languages solve this in different ways.
What exactly do you mean by including the cpp file with the definition and decoration?
I tend to include headers in headers simply to keep definitions away and nicely structured for the reader. Correct me if I’m wrong, but can you not simply use the ifndef preprocessor to check if the header has already been included and if not, then include?
I’m not sure I understood your comment. Who’s supposed to use the ifndef preprocessor to check if the header has already been included, and why?
Eclipse CDT has a neat “organize includes” feature. It will add any includes needed in the open file, and remove any unneeded includes. You need to run it on each file separately, and then it will effectively move #include statements from the .h file tree to the .h/.cpp files that actually use those included files.
Nice, that sounds really useful!