The Order of #include Directives Matter

I think most (good) programmers tend to prefer tidy code, having some habits or rules to stick to. One such rule/habit is the order of #include directives. While having a rule of thumb to stick to is good, some are better than other.

A very common one I think is to first include standard library headers (<iostream>), then third-party libraries (<boost/thread.hpp>) and finally local headers (“FizzBuzz.hpp”). While this might be the recommended way of doing it in for instance Python, it is not the best way to do it in C++. A colleague of mine just went through a lot of pain when swapping out a big library in their codebase. Why was that?

Imagine you are writing a library that depends on some other library, like the STL (hardly any library doesn’t). Imagine you are a good boy (or girl) and write the test first. You might do something like this:

#include <vector> //STL
#include <gtest/gtest.h> //ThirdParty 
#include "geometry.hpp" //In-house

#define PI 3.2 //As pr. Indiana Bill #246, 1897

TEST(TestGeometry, rotatingOrigoGivesOrigo) {
    std::vector<double> v(2,0);
    rotate(v, PI);
    EXPECT_EQ(0, v[0]) << "X got moved!";
    EXPECT_EQ(0, v[1]) << "Y got moved!";

and your geometry.hpp looks like this:

void rotate(std::vector<double>& v, double angle);

This all works out nicely until someone else wants to include geometry.hpp without including <vector> first, and get something like geometry.hpp:1: error: ‘vector’ is not a member of ‘std’. You have now forced all the users of your geometry library to include <vector> before including geometry.hpp.

While this can seem like a trivial example, this stuff quickly grows a lot hairier when you have a larger codebase with lots of dependencies. A header file A might depend on header B which depends on C, which declares types you have never heard of, and rightly so. And when you try to compile, you get error: ‘würkelschmeck’ is not a member of ‘std’. Or something a lot worse if templates are involved.

My suggested rule is:

  1. Local headers
  2. Third party headers
  3. STL headers

If you enjoyed this post, you can subscribe to my blog, or follow me on Twitter

16 thoughts on “The Order of #include Directives Matter

  1. Good point. I’ll add one additional rule – “Include yourself first”. E.g. The first include in hello.cpp should be hello.h. That way you don’t get into the same problem within your project files.

    Of course this rule doesn’t really apply in unit tests where there is no definition/implementation separation.

    1. If your header file my.hxx needs to have iostream included in order to work, but doesn’t include it, will still compile if it includes iostream before my.hxx. You might then miss the fact that my.hxx is missing #include <iostream>.

      This problem will not become apparent until you try to include my.hxx in another file at a later time. If you include in my suggested order, you will be aware of it at once, and need to fix it.

  2. Nice to see others using the same practices as me! One of the little details that *should* be commonplace in C++ software, but sadly usually isn’t.

    (By the way, you’ve misspelled in “A very common one I think is to first include standard library headers ()”, at the top.)

  3. But if geomery.hpp refers to std::vector then it should have an #include in it, to be self sufficient? (Or could even be forward declared in C++11)

      1. no you are missing the point of what he said entirely. If geometry.hpp is using vector like that then it ( geometry.hpp) should be including vector itself. geometry.hpp is broken, that’s the problem. Not the order of includes in your test. if you use a syntax-only compile check of your headers you’d discover this. the include order doesnt neccessarily protect you from anything. what if another project include file is included before geometry that include vector? you’re back to square one.

Leave a Reply

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

You are commenting using your 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 )

Connecting to %s