Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

including files best practice

72 views
Skip to first unread message

ouroboros84

unread,
Nov 14, 2013, 4:34:49 PM11/14/13
to
Please find here below a simple example. I know that a .hpp file has to include or forward declare everything it uses I wonder if it is best practice to include all .hpp files that are used in the .cpp file as well. I am asking this because I recently saw on a new project I am working on, that people tend to avoid including headers in a lot of cpp files.

In this case: is it good to include b.hpp in a.cpp? I know it has already been included by including a.hpp, but I personally feel that if a symbol appears in a .cpp, it should be included (or forward declared if possible)

a.hpp

#pragma once
#include "b.hpp"

class C; //forward declaration of C

class A
{
public:
B get_b();
private:
B _b;
C* _c;
};

a.cpp

#include "a.hpp"
//needed or I can leave it out, since B is included already in a.hpp?
#include "b.hpp"

B A::get_b()
{
return _b;
}

Jorgen Grahn

unread,
Nov 14, 2013, 5:14:02 PM11/14/13
to
On Thu, 2013-11-14, ouroboros84 wrote:
> Please find here below a simple example. I know that a .hpp file has
> to include or forward declare everything it uses

It doesn't /have to/ -- although it can be rather confusing if a file
which just says #include "foo.hpp" doesn't compile.

> I wonder if it is
> best practice to include all .hpp files that are used in the .cpp file
> as well. I am asking this because I recently saw on a new project I am
> working on, that people tend to avoid including headers in a lot of
> cpp files.

No, that's not best practice.

> In this case: is it good to include b.hpp in a.cpp? I know it has
> already been included by including a.hpp, but I personally feel that
> if a symbol appears in a .cpp, it should be included (or forward
> declared if possible)

My personal rule is this: if I have a pair foo.cpp/foo.hpp, I always
do a

#include "foo.hpp"

first in that cpp file. That's an automatic check that foo.hpp is
idempotent. Then you can do almost whatever you want and not end up
with a nasty effects like "I included foo.hpp from a new source file,
and had to spend half an hour finding out which other files I needed
to pull in first".

I try not to have a foo.hpp pull in a /lot/ of other headers which it
doesn't really need, but it's not a big disaster if it it pulls in a
few too many.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Victor Bazarov

unread,
Nov 14, 2013, 5:27:48 PM11/14/13
to
I second this.

I would include it since 'B' type is used in a.cpp. Cannot (and should
not) rely on 'b.hpp' being pulled in by 'a.hpp'.

Of course, it's a style question, not a necessity. If it's pulled in
twice, it should contain the double inclusion guards, etc. And if it's
not included after somebody edits 'a.hpp' file, an attempt to compile
'a.cpp' will reveal that. But I still include all those things, myself.

V
--
I do not respond to top-posted replies, please don't ask

ouroboros84

unread,
Nov 14, 2013, 5:29:30 PM11/14/13
to
Il giorno giovedì 14 novembre 2013 23:14:02 UTC+1, Jorgen Grahn ha scritto:
> On Thu, 2013-11-14, ouroboros84 wrote:
>
>
> > I wonder if it is
>
> > best practice to include all .hpp files that are used in the .cpp file
>
> > as well. I am asking this because I recently saw on a new project I am
>
> > working on, that people tend to avoid including headers in a lot of
>
> > cpp files.
>
>
>
> No, that's not best practice.
>
>
>

Imagine though, if now in a.cpp you had this, as you suggest:

#include "a.hpp"
//#include "b.hpp" deleted

B A::get_b()
{
return _b;
}

namespace {
B b; //I can instanciate it
// even if I don't have the header
//thanks to an im[licit inclusion from a.hpp
C = b.get_c() //I can do it as well because a.hpp -> b.hpp -> c.hpp
}


wouldn't that cause problems? imagine if someone deleted c.hpp inclusion from b.hpp, using a forward declare for returning a reference instead of a value.
in that case a.cpp wouldn't compile anymore.

I prefer to be explicit in what I have to include in every class.
for example it is rare that you need to include a <string> header, but you basically do it every time you use a string.

ouroboros84

unread,
Nov 14, 2013, 5:33:50 PM11/14/13
to
thanks, I prefer to include them myself too. I was just wondering if there was a common agreement in the C++ commmunity, but as usual it seems there isn't one :-)

Jorgen Grahn

unread,
Nov 14, 2013, 5:55:54 PM11/14/13
to
On Thu, 2013-11-14, ouroboros84 wrote:
> Il giorno gioved� 14 novembre 2013 23:14:02 UTC+1, Jorgen Grahn ha scritto:
>> On Thu, 2013-11-14, ouroboros84 wrote:
>>
>>
>> > I wonder if it is
>>
>> > best practice to include all .hpp files that are used in the .cpp file
>>
>> > as well. I am asking this because I recently saw on a new project I am
>>
>> > working on, that people tend to avoid including headers in a lot of
>>
>> > cpp files.
>>
>>
>>
>> No, that's not best practice.
>
> Imagine though, if now in a.cpp you had this, as you suggest:

I'm not sure I suggested that. However ...

>
> #include "a.hpp"
> //#include "b.hpp" deleted
>
> B A::get_b()
> {
> return _b;
> }
>
> namespace {
> B b; //I can instanciate it
> // even if I don't have the header
> //thanks to an im[licit inclusion from a.hpp
> C = b.get_c() //I can do it as well because a.hpp -> b.hpp -> c.hpp
> }

> wouldn't that cause problems? imagine if someone deleted c.hpp
> inclusion from b.hpp, using a forward declare for returning a
> reference instead of a value. in that case a.cpp wouldn't compile
> anymore.

I have a hard time following your examples; I can't remember a c.hpp
in your first posting.

But anyway: ok, so someone removes an #include from some header file,
because it's not strictly needed there. And building something else
fails.

For me that's perfectly fine. I have all the sources; I can rearrange
them as needed. I myself was probably that someone who made the
change, a few seconds earlier -- because noone would change a header
file and commit without checking if it at least built!

I guess this means I'm assuming you're not developing isolated
components or libraries. Things are different and a lot harder if you
do. But (a) very few people need to do that, and (b) there are
several other worries you have in that case.

It /is/ a real problem for library writers and users though: many
times I've upgraded my compiler or standard library and had code stop
building, because #include <iostream> no longer pulls in <ostream>, or
something. I see no way around this.

Alf P. Steinbach

unread,
Nov 14, 2013, 6:46:03 PM11/14/13
to
On 14.11.2013 22:34, ouroboros84 wrote:
[snip]
> a.cpp
>
> #include "a.hpp"
> //needed or I can leave it out, since B is included already in a.hpp?
> #include "b.hpp"
>
> B A::get_b()
> {
> return _b;
> }

In this case the full class B definition is not needed for class A's
public interface. So there is a possibility that class A will be changed
so that [b.hpp] is not needed for [a.hpp]. However, changing [a.hpp]
will usually be accompanied by a corresponding change of [a.cpp], so
there's problem with THIS file, whatever you decide.

The main problem is with client code. A programmer using [a.hpp] cannot
know whether [b.hpp] is guaranteed made available or is just present as
an implementation aspect that might be changed at any time. That's
because the complete class B definition is not needed for A's /public/
interface, only for its implementation, and so some optimization of
class A (e.g. for build time) might result in [b.hpp]'s removal.

So if I was concerned about this kind of problem then I would document
in some way whether [b.hpp] is present by design or as just an
implementation aspect.


* * *

In some cases you absolutely know that a header will be made available
by some other header. For example, a header that exposes something that
involves Windows API things will, as a rule, guaranteed include
<windows.h>. But that does not mean that client code can avoid including
<windows.h>. On the contrary, that Microsoft header, the "mother of all
headers", provides a set of declarations that depends strongly on
various macro symbols, plus that a great many of the declarations
themselves depend on various macro symbols. Thus to ensure consistent
declarations and a consistent set of declarations, it is a good idea to
include this header before including headers that depend on it. Other
3rd party headers may be similarly badly designed.

* * *

To ensure that headers are free-standing (that they're "idempotent")
it's a good idea to include each header at the top in /some/ [.cpp]
file. For header only modules I use a dummy [.cpp] file. E.g.,
[blahblah.h] is included by [blahblah.h.dummy.cpp], if it isn't included
by a real implementation file [blahblah.cpp].

With some toolsets (in particular Microsoft's) this necessitates turning
off librarian warnings about unused stuff.

Also note that this practice ties in with the previous section, ensuring
that those headers that need some H do include it.

* * *

Microsoft's precompiled header feature, which is on by default in a
Visual Studio project, can make incorrect code compile and can cause
errors with correct code. It's no big deal to adjust the code but it
means that code compiled with this feature may not necessarily work with
some other compiler. I do not know of any good solution.


Cheers & hth.,

- Alf

Tobias Müller

unread,
Nov 15, 2013, 2:24:12 AM11/15/13
to
"Alf P. Steinbach" <alf.p.stein...@gmail.com> wrote:
> Microsoft's precompiled header feature, which is on by default in a
> Visual Studio project, can make incorrect code compile and can cause
> errors with correct code. It's no big deal to adjust the code but it
> means that code compiled with this feature may not necessarily work with
> some other compiler. I do not know of any good solution.

I know you are not reading my posts but maybe someone else can explain
that.
I always use precompiled headers and never had problems with them.
Given that they are set up correctly of course.

Tobi

Paavo Helde

unread,
Nov 15, 2013, 3:53:51 AM11/15/13
to
=?UTF-8?Q?Tobias=20M=C3=BCller?= <tro...@bluewin.ch> wrote in
news:1507027537406192681.37...@news.eternal-
september.org:
There is a bug in MSVC that any code before #include "precompiled.h" line
is ignored. For ignored #include lines they issue a warning, but other code
is ignored silently. I guess this is what Alf meant.

Cheers
Paavo

Juha Nieminen

unread,
Nov 15, 2013, 5:14:59 AM11/15/13
to
Jorgen Grahn <grahn...@snipabacken.se> wrote:
> I try not to have a foo.hpp pull in a /lot/ of other headers which it
> doesn't really need, but it's not a big disaster if it it pulls in a
> few too many.

It's not a disaster, but in general one ought to minimize the number
of #includes (especially when they refer to files inside the same
project, rather than eg. system headers).

In small projects it's mostly inconsequential. However, the larger the
project, the more important it becomes to minimize the number of #include
lines. The more inter-dependency there is between source files and
header files, the longer the building process becomes even from very
small changes. If a change in one header file causes 5 source files to
be recompiled, that's a much nicer result than if it causes 50 source
files to be recompiled (especially when you are developing/debugging
the project and you are doing a lot of test builds frequently.)

Of course one shouldn't go overboard with this and start to make the
program more complex or inefficient just for the sake of avoiding a
few #includes, but in cases where it doesn't otherwise affect the
complexity or efficiency of the program, it's something to keep in mind.


--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

Alf P. Steinbach

unread,
Nov 15, 2013, 7:59:41 AM11/15/13
to
Yep.

Thanks,

- Alf


James Kanze

unread,
Nov 15, 2013, 12:35:45 PM11/15/13
to
In general, I would agree. But one can consider this a special
case; if the definition of A requires a full definition of B,
then A must have included b.hpp, and of course, in a.cpp, you
know this, because you are implementing the private parts of A.
So it doesn't seem as essential to me as it normally would be.

--
James
0 new messages