I'm very fastidious about code. When I remove functionality from a file I remove the cooresponding #includes. I've hit several errors where I would remove a #include from a header, and another file that #included the header I was editing depended on that #include.

Depending on the error given by the compiler it can waste a fair amount of my time determining which dependency I actually removed.

I've been told by a coworker, that the problem is that I'm cleaning up #includes when I should just leave them alone even if nothing in their contents is used. He claims that if we fully specified our includes top level files would be ridiculously bloated.

I'd like a convincing argument to sway him to fully specify the necessary #includes. Or perhaps I'm in the wrong in which case I'd like to hear an argument against me cleaning up #includes. Is there an argument convincing enough to sway one of us?

  • Frankly, I don't see this as a good cause for a religious debate. The only reason to keep header inclusion small is to reduce compile times. If it's easy to reduce #includes, do it, if it ain't, don't. Likewise, forgetting a direct #include where a header already provides it indirectly, is pretty harmless. The thing that really makes me uneasy is that you say that you can't easily track down the necessary includes from the error messages that you are given. Normally it should be easy to grep the source for the symbol that the compiler's complaining about. So what makes it hard for you? – cmaster - reinstate monica Oct 17 '15 at 7:32
  • 2
    Track down Google's "include what you use" (IWYU) software — now on Github — for a take that more or less agrees with you. – Jonathan Leffler Oct 17 '15 at 9:39
  • @cmaster Because when it happens I expect that the error was caused by something in my code. When I recognize it's an include problem it's obviously pretty simple to fix. – Jonathan Mee Oct 17 '15 at 11:42

You are following consensus expert practice in C++. A source file should #include the header files for all its direct dependencies. You are getting compile errors, so what's the problem? First you clean up a header file, then you go fix the broken .cpp files. Then you commit the code.

| improve this answer | |
  • You're right, I should just keep doing the right thing. It's just a hassle, that continues to propagate. My coworker writes code that's dependent, I clean up a file, I break his code, I fix his code, and round we go. If one of us is in fact right I'd like to stop the cycle. – Jonathan Mee Oct 17 '15 at 11:48

There are (at least) four options available:

1. Keep unnecessary #includes in the header files as the OP's colleague insists on

This has the following effects:

  • (positive) You do not break software that is currently working.
  • (positive) You do not have to do much work now.
  • (negative) Dependencies remain hidden: which part of the program depends on what other parts remain a mystery.

    Hidden/implicit dependencies might cause:

    • Keeping dependencies on parts that are no longer used. Which might cause you to have to work to keeps these parts integrated; e.g. "we have to update {unknowingly obsolete part} to the new {foo thingy}", or "we have to implement {very useful feature} in an awkward way since we cannot make use of the nice features in {foo thingy v2.0} since {unknowingly obsolete part} has to use {foo thingy v1.7}.
    • Difficulties to understand the software and its structure: especially for new developers but seasoned team member will also spend more time finding were something went wrong.
  • (possibly positive) In some specific situations keeping the #includes as is may preserve the layout of the compiled binaries which allows parts of them to be patched. But preserving the ABI requires you to be very careful with your changes and how you implement them. I would be surprised if you team/company relies on binary compatibility between minor version of your software; to my assumption most software updates are done by replacing entire files or even collections of files (programmers.SE community, please correct me if my assumptions are wrong).

2. As the OP, Jonathan Mee, does and as Kevin Cline suggests:

  1. when a file no longer depends on some headers, remove the #included headers one by one;
  2. compile the code and see which .cpp files break;
  3. #include the removed header in the .cpp files that break.

    Note, always keep the header that defines the class implemented in the .cpp as the header included first (e.g. the file myClass.cpp should have #include "myClass.h" as its first non-comment line). When adding an#includefor the removed header to a .cpp file does fix that file's compilation errors, a header depends on the removed head and you should add the#include` there.

This has the following effects:

  • You spend some effort now compiling and tracing errors caused by missing includes.
  • (negative) Code file may become bloated with a large list of includes, as the OP's colleague argues.
  • (negative) Tomorrow you will run into an other instance of this same problem.
  • Code has a little fewer implicit dependencies, but the overall difficulty/ease of understanding the code remains the same.

3. Create headers with #includes commonly used together

For example, when many .cpp or .h files #include "foo.h", #include "bar.h", and #include "baz.h, instead of adding these three lines to every .cpp file that uses the headers, create a header that only #includes these three headers (and does not define anything else) and #include that header.

  • (positive) You avoid your code files to become as bloated as your colleague fears; perhaps saying him to your (and the experts's side).

  • (negative) Both in your current situation with no longer directly used #includes still in header files and in this proposed «solution» not being bloated is appearance in reality it still is bloated and you're still suffering most negative effects in both this approach and that of your current situation.*

  • (positive) You can evolve the common headers as you are cleaning up unused functionality; so there is not that much more work to do as in approach #2.
  • (positive) As you «evolve» the common header files an organisation into package might reveal itself. This improves the ease of understanding the software and its organisation of dependencies.

4. Reorganise the software such no longer everything depends on other parts all over the system

The stale includes and the .cpp files becoming bloated when they #include the headers they require are signs of the software not organised as well as it could be.

  • (positive) Better organisation leads to systems that are easier to understand.
  • (positive) Better organisation leads to systems that are easier to change.
  • (negative) Reorganising the system into packages with restricted dependencies is much work; it might require rewriting many parts.
  • (positive) You can remove unused #includes and move them to where they are needed without the source files becoming bloated with #includes (this time for real and not just mere appearances).
  • (negative) Reorganising the system and rewriting parts might cause you to introduce bugs.
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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