Your preferred C/C++ header policy for big projects?

C++CCoding StyleIncludeHeader

C++ Problem Overview


When working on a big C/C++ project, do you have some specific rules regarding the #include within source or header files?

For instance, we can imagine to follow one of these two excessive rules:

  1. #include are forbidden in .h files; it is up to each .c file to include all the headers it needs
  2. Each .h file should include all its dependancies, i.e. it should be able to compile alone without any error.

I suppose there is trade-off in between for any project, but what is yours? Do you have more specific rules? Or any link that argues for any of the solutions?

C++ Solutions


Solution 1 - C++

If you include H-files exclusively into C-files, then including a H-file into a C-file might cause compilation to fail. It might fail because you may have to include 20 other H-files upfront, and even worse, you have to include them in the right order. With a real lot of H-files, this system ends up to be an administrative nightmare in the long run. All you wanted to do was including one H-file and you ended up spending two hours to find out which other H-files in which order you will need to include as well.

If a H-file can only be successfully included into a C-file in case another H-file is included first, then the first H-file should include the second one and so on. That way you can simply include every H-file into every C-file you like without having to fear that this may break compilation. That way you only specify your direct dependencies, yet if these dependencies themselves also have dependencies, its up to them to specify those.

On the other hand, don't include H-files into H-files if that isn't necessary. hashtable.h should only include other header files that are required to use your hashtable implementation. If the implementation itself needs hashing.h, then include it in hashtable.c, not in hashtable.h, as only the implementation needs it, not the code that only would like to use the final hashtable.

Solution 2 - C++

I think both suggested rules are bad. In my part I always apply:

Include only the header files required to compile a file using only what is defined in this header. This means:

  1. All objects present as reference or pointers only should be forward-declared
  2. Include all headers defining functions or objects used in the header itself.

Solution 3 - C++

I would use the rule 2:

All Headers should be self-sufficient, be it by:

  • not using anything defined elsewhere
  • forward declaring symbols defined elsewhere
  • including the headers defining the symbols that can't be forward-declared.

Thus, if you have an empty C/C++ source file, including an header should compile correctly.

Then, in the C/C++ source file, include only what is necessary: If HeaderA forward-declared a symbol defined in HeaderB, and that you use this symbol you'll have to include both... The good news being that if you don't use the forward-declared symbol, then you'll be able to include only HeaderA, and avoid including HeaderB.

Note that playing with templates makes this verification "empty source including your header should compile" somewhat more complicated (and amusing...)

Solution 4 - C++

The first rule will fail as soon as there are circular dependencies. So it cannot be applied strictly.

(This can still be made to work but this shifts a whole lot of work from the programmer to the consumer of these libraries which is obviously wrong.)

I'm all in favour of rule 2 (although it might be good to include “forward declaration headers” instead of the real deal, as in <iosfwd> because this reduces compile time). Generally, I believe it's a kind of self-documentation if a header file “declares” what dependencies it has – and what better way to do this than to include the required files?

EDIT:

In the comments, I've been challenged that circular dependencies between headers are a sign of bad design and should be avoided.

That's not correct. In fact, circular dependencies between classes may be unavoidable and aren't a sign of bad design at all. Examples are abundant, let me just mention the Observer pattern which has a circular reference between the observer and the subject.

To resolve the circularity between classes, you have to employ forward declaration because the order of declaration matters in C++. Now, it is completely acceptable to handle this forward declaration in a circular manner to reduce the number of overall files and to centralize code. Admittedly, the following case doesn't merit from this scenario because there's only a single forward declaration. However, I've worked on a library where this has been much more.

// observer.hpp

class Observer; // Forward declaration.

#ifndef MYLIB_OBSERVER_HPP
#define MYLIB_OBSERVER_HPP

#include "subject.hpp"

struct Observer {
    virtual ~Observer() = 0;
    virtual void Update(Subject* subject) = 0;
};

#endif

// subject.hpp
#include <list>

struct Subject; // Forward declaration.

#ifndef MYLIB_SUBJECT_HPP
#define MYLIB_SUBJECT_HPP

#include "observer.hpp"

struct Subject {
    virtual ~Subject() = 0;
    void Attach(Observer* observer);
    void Detach(Observer* observer);
    void Notify();

private:
    std::list<Observer*> m_Observers;
};

#endif

Solution 5 - C++

A minimal version of 2. .h files include only the header files it specifically requires to compile, using forward declaration and pimpl as much as is practical.

Solution 6 - C++

  1. Always have some sort of header guard.
  2. Do not pollute the user's global namespace by putting any using namespace statements in a header.

Solution 7 - C++

I'd recommend going with the second option. You often end up in the situation where you want to add somwhing to a header file that suddenly requires another header file. And with the first option, you would have to go through and update lots of C files, sometimes not even under your control. With the second option, you simply update the header file, and the users who don't even need the new functionality you just added needn't even know you did it.

Solution 8 - C++

The first alternative (no #includes in headers) is a major no-no for me. I want to freely #include whatever I might need without worrying about manually #includeing its dependencies as well. So, in general, I follow the second rule.

Regarding cyclic dependencies, my personal solution is to structure my projects in terms of modules rather than in terms of classes. Inside a module, all types and functions may have arbitrary dependencies on one another. Across module boundaries, there may not be circular dependencies between modules. For each module, there is a single *.hpp file and a single *.cpp file. This ensures that any forward declarations (necessary for circular dependencies, which can only happen inside a module) in a header are ultimately always resolved inside the same header. There is no need for forward-declaration-only headers whatsoever.

Solution 9 - C++

Pt. 1 fails when you would like to have precompiled headers through a certain header; eg. this is what StdAfx.h are for in VisualStudio: you put all common headers there...

Solution 10 - C++

This comes down to interface design:

  1. Always pass by reference or pointer. If you aren't going to check the pointer, pass by reference.
  2. Forward declare as much as possible.
  3. Never use new in a class - create factories to do that for you and pass them to the class.
  4. Never use pre-compiled headers.

In Windows my stdafx only ever includes afx___.h headers - no string, vector or boost libraries.

Solution 11 - C++

Rule nr. 1 would require you to list your header files in a very specific order (include files of base classes must go before include files of derived classes, etc), which would easily lead to compilation errors if you get the order wrong.

The trick is, as several others have mentioned, use forward declarations as much as possible, i.e. if references or pointers are used. To minimize build dependencies in this way the pimpl idiom can be useful.

Solution 12 - C++

I agree with Mecki, to put it shorter,

for every foo.h in your project include only those headers that are required to make

// foo.c
#include "any header"
// end of foo.c

compile.

(When using precompiled headers, they are allowed, of course - e.g. the #include "stdafx.h" in MSVC)

Solution 13 - C++

Personally I do it this way:
1 Perfer forward declare to include other .h files in a .h file. If something could be used as pointer/reference in that .h files or class, forward declare is possible without compile error. This could make headers less include dependencies(save compile time? not sure:( ).
2 Make .h files simple or specific. e.g. it is bad to define all constances in a file called CONST.h, it is better to divid them into multiple ones like CONST_NETWORK.h, CONST_DB.h. So to use one constance of DB, it needn't to include other information about network.
3 Don't put implementation in headers. Headers are used to quick review public things for other people; when implementing them, don't pollute declaration with detail for others.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestioncalandoaView Question on Stackoverflow
Solution 1 - C++MeckiView Answer on Stackoverflow
Solution 2 - C++PierreBdRView Answer on Stackoverflow
Solution 3 - C++paercebalView Answer on Stackoverflow
Solution 4 - C++Konrad RudolphView Answer on Stackoverflow
Solution 5 - C++David SykesView Answer on Stackoverflow
Solution 6 - C++FerruccioView Answer on Stackoverflow
Solution 7 - C++dkagedalView Answer on Stackoverflow
Solution 8 - C++pyonView Answer on Stackoverflow
Solution 9 - C++Marcin GilView Answer on Stackoverflow
Solution 10 - C++graham.reedsView Answer on Stackoverflow
Solution 11 - C++andreas buykxView Answer on Stackoverflow
Solution 12 - C++peterchenView Answer on Stackoverflow
Solution 13 - C++SteelView Answer on Stackoverflow