10

I'm currently creating a project that utilized a lot of forward declarations and such so I've come across an issue where my #includes seem to be extremely redundant.

Example:

config.h

#include <Windows.h>
#include <vector>

config.cpp

#include "config.h"
#include "resolve.h"
#include <Windows.h>
#include <vector>
//functions that use extern functions/variables.

resolve.cpp

#include "config.h"
#include "resolve.h"
#include <iostream>
#include <Windows.h>
#include <winternl.h>
#include <TlHelp32.h>
//functions that use extern functions/variables.

main.cpp

#include "config.h"
#include "resolve.h"
#include <iostream>
//functions that use extern functions/variables.

Would it be better for me to do something like flow them so there aren't any duplicate #includes for something like this?

config.h

#include <vector>
#include <iostream>
#include <Windows.h>
#include <winternl.h>
#include <TlHelp32.h>
//declarations for config.cpp

resolve.h

#include "config.h"
//declarations for resolve.cpp

config.cpp

#include "resolve.h"

resolve.cpp

#include "resolve.h"

main.cpp

#include "resolve.h"

So this way everything already has the headers they need + the forward declarations?

2 Answers 2

12

Normal best practice is for every file to include all the header files it requires, disregarding #include directives in included files. Each header file should then have a construct like this so that it's contents are only included once:

#ifndef _HEADER_FILE_NAME_H
#define _HEADER_FILE_NAME_H

.... header file contents

#endif

This takes care of redundancy by insuring the contents are only included once, the first time the file is included. Subsequent inclusions will skip the contents because the guard symbol was defined during the first inclusion.

5
  • 1
    Only disregarding nested includes if they are part of the implementation instead of the interface. It's fine to have a header including (lots of) others, and relying on those includes. Commented Sep 21, 2016 at 11:53
  • 2
    #pragma once may be considered instead of #ifndefblock.
    – Q Q
    Commented Sep 21, 2016 at 13:52
  • @Deduplicator Even then it should disregard them. If header X requires A, B and C because they're part of it's exposed interface it should include A, B and C and disregard the fact that A also includes B and C. Let the @ifndef or #pragma once handle the redundancy. That also immunizes X from being affected if A changes so it no longer needs to include B or C.
    – Todd Knarr
    Commented Sep 21, 2016 at 16:09
  • @QQ that's fine if you only ever have to compile with the Microsoft compiler, but that won't work with any other compiler IIRC.
    – RubberDuck
    Commented Sep 21, 2016 at 23:59
  • 3
    @RubberDuck It's more widely supported than that. GCC's supported it since 3.4, Clang supports it, Intel and IBM and HP compilers support it. It's not standard but it's not a high portability risk.
    – Todd Knarr
    Commented Sep 22, 2016 at 1:22
3

Once you have adopted #include guards or #pragma once as proposed by Todd Knarr in the other answer, redundant includes are technically no longer an issue.

However, your question would still remain: should the headers be included explicitly everywhere they are potentially needed ? Or should they be nested one in another, like matriochka dolls, in order to reduce the number of includes ?

Make headers self sufficient

If you need a resolver, just include resolve.h. You shouldn't have to worry what other headers you would need for it to work.

So if the declaration in resolve.h would depend somehow on config.h, include it in the first header. The huge advantage, is that if you'd one day refactor the resolver, and get rid of its dependency to config.h, or if on contrary you'd add a new dependency to resolve_base.h, you'd just change this in one header : a very good example of separation of concerns.

Reinforce encapsulation and keep coupling to its minimum

It is possible that resolve.cpp needs additional includes, for example windows.h or iostream because the implementation depends on other compilation units. If these includes are not required by resolve.h they are an implemetnation detail: don't created unnecessary couplings; don't include them there: the users of resolve.h don't need to know these dependencies. Include them only in resolve.cpp. This gives you flexibility to change the implementation, without having to propagate changes that should not affect other modules.

Convenience and speed

There are some includes that you use in many many compilation units. It could then be a pragmatic approach to include these in a common header that you would then include in all the implementation files:

  • less explicit dependencies
  • but a lot of typing less (and avoidance of error message caused by forgotten headers).

This can be further justified if your compiler uses pre-compiled headers (e.g. stdafx.h with MSVC).

Aditional reading

1
  • 1
    Cannot believe this answer did not have any upvotes yet. Very useful!
    – djvg
    Commented Jun 19, 2019 at 20:02

Not the answer you're looking for? Browse other questions tagged or ask your own question.