Another Reason to Avoid #includes in Headers


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 file[1-4].h.

In c++, #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. file6.cpp and 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.

What if 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.

3 Responses to “Another Reason to Avoid #includes in Headers”

  1. Dan Says:

    Anders,

    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.

    • Anders Schau Knatten Says:

      Hi Dan,

      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.)

  2. How to avoid includes in headers « C++ on a Friday Says:

    […] Another Reason to Avoid #includes in Headers […]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 392 other followers

%d bloggers like this: