0

When I started learning C++ I learned that header files should typically be #included in other header files. Just now I had someone tell me that I should include a specific header file in my .cpp file to avoid header include creep.

Could someone tell me what exactly that is, why it is a problem and maybe point me to some documentation on when I would want to include a file in another header and when I should include one in a .cpp file?

sashoalm
  • 75,001
  • 122
  • 434
  • 781
joshu
  • 463
  • 8
  • 18
  • 2
    Why dont you ask this guy what he means with header include creep? – 463035818_is_not_an_ai Mar 06 '15 at 17:11
  • 1
    You avoid header-creep by forward declaring pointers instead of including their definitions. – sashoalm Mar 06 '15 at 17:12
  • Given that google shows nothing relevant to programming for "header include creep", I'm guessing the person made up the term and/or concept. – crashmstr Mar 06 '15 at 17:14
  • 2
    @crashmstr: Or he's just using regular English words, not technical jargon, to describe the phenomenon of including one header and dragging in many others that you didn't expect, leading to annoyances like unnecessary recompilation, and errors like circular inclusion. – Mike Seymour Mar 06 '15 at 17:17

5 Answers5

2

Could someone tell me what exactly [include creep] is

It's not a programming term, but interpreting it in an Engish-language context would imply that it's the introduction of #include statements that are not necessary.

why it is a problem

Because compiling code takes time. So compiling code that's not necessary takes unnecessary time.

and maybe point me to some documentation on when I would want to include a file in another header and when I should include one in a .cpp file?

If your header requires the definition of a type, you will need to include the header that defines that type.

#include "type.h"

struct TypeHolder
{
    Type t;
//  ^^^^ this value type requires the definition to know its size.
}

If your header only requires the declaration of a type, the definition is unnecessary, and so is the include.

class Type;     

struct TypeHolder
{
    Type * t;
//  ^^^^^^ this pointer type has the already-known size of a pointer,
//         so the definition is not required.
}

As an anecdote that supports the value of this practice, I was once put on a project whose codebase required ONE HOUR to fully compile. And changing a header often incurred most or all of that hour for the next compilation.

Adding forward-declarations to the headers where applicable instead of includes immediately reduced full compilation time to 16 minutes, and changing a header often didn't require a full rebuild.

Drew Dormann
  • 59,987
  • 13
  • 123
  • 180
2

The "creep" refers to the inclusion of one header including many others. This has some unwanted consequences:

  • a tendency towards every source file indirectly including every header, so that a change to any header requires everything to be recompiled;
  • more likelihood of circular dependencies causing heartache.

You can often avoid including one header from another by just declaring the classes you need, rather than including the header that gives the complete definition. Such an incomplete type can be used in various ways:

// Don't need this
//#include "thingy.h"

// just this
class thingy;

class whatsit {

    // You can declare pointers and references
    thingy * p;
    thingy & r;

    // You can declare static member variables (and external globals)
    // They will need the header in the source file that defines them
    static thingy s;

    // You can declare (but not define) functions with incomplete
    // parameter or return types
    thingy f(thingy);
};

Some things do require the complete definition:

// Do need this
#include "thingy.h"

// Needed for inheritance
class whatsit : thingy {

    // Needed for non-static member variables
    thingy t;

    // Needed to do many things like copying, accessing members, etc
    thingy f() {return t;}
};
Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
1

Well they were probably referring to a couple of things ("include creep" is not a term I've ever heard before). If you, as an extreme rule, only include headers from headers (aside from one matching header per source file):

  • Compilation time increases as many headers must be compiled for all source files.
  • Unnecessary dependencies increase, e.g. with a dependency based build system, modifying one header may cause unnecessary recompilation of many other files, increasing compile time.
  • Increased possibility of namespace pollution.
  • Circular dependencies become an issue (two headers that need to include each other).
  • Other more advanced dependency-related topics (for example, this defeats the purpose of opaque pointers, which causes many design issues in certain types of applications).

As a general rule of thumb, include the bare minimum number of things from a header required to compile only the code in that header (that is, enough to allow the header to compile if it is included by itself, but no more than that). This will combat all of the above issues.

For example, if you have a source file for a class that uses std::list in the code, but the class itself has no members or function parameters that use std::list, there's no reason to #include <list> from the class's header, as nothing in the class's header uses std::list. Do it from the source file, where you actually need it, instead of in the header, where everything that uses the class also has to compile <list> unnecessarily.

Another common technique is forward declaring pointer types. This is the only real way to combat circular dependency issues, and has some of the compilation time benefits listed above as well. For example, if two classes refer to each other but only via pointers:

// A.h
class B; // forward declaration instead of #include "B.h"
class A {
   B *b;
}

// B.h
class A; // forward declaration instead of #include "A.h"
class B {
   A *a;
}

Then include the headers for each in the source files, where the definitions are actually needed.

Jason C
  • 38,729
  • 14
  • 126
  • 182
0

Your header files should include all headers they need to compile when included alone (or first) in a source file. You may in many cases allow the header to compile by using forward declarations, but you should never rely on someone including a specific header before they include yours.

Mark B
  • 95,107
  • 10
  • 109
  • 188
0

theres compie time to think of, but there's also dependancies. if A.h includes B.h and viceversa, code won't compile. You can get around this by forward referancing your class, then including the header in the cpp

A.h

class B;
class A
{
    public:
    void CreateNewB():
    private:
    B* m_b;
};

A.cpp

#include "B.h"

A::CreateNewB()
{
   m_b = new B;
}
cool mr croc
  • 725
  • 1
  • 13
  • 33