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

Header file question

76 views
Skip to first unread message

Joseph Hesse

unread,
Mar 25, 2015, 9:46:43 AM3/25/15
to
The following 3 file program was constructed so I could get advice with
header file inclusion. The program compiles and run fine.

= Funcs.h =============================
#ifndef FUNCS_H
#define FUNCS_H

#include <vector>

double sum(std::vector<double> &vd);

#endif
= Funcs.cpp ===========================
#include "Funcs.h"

double sum(std::vector<double> &vd)
{
double s = 0.0;

for(const double &d : vd)
s += d;

return s;
}
= Test.cpp ============================
#include <iostream>
#include "Funcs.h"

int main()
{
std::vector<double> numbers = {1.5, 2.5, 3.5, 4.5};

std::cout << "The sum is " << sum(numbers) << std::endl;

return 0;
}
=======================================

1. In Funcs.cpp the file Funcs.h was included since it seems like best
practices for an X.cpp to always include an X.h. However one could
argue that someone reading Funcs.cpp would see the use of the type
vector<double> and therefore #include <vector> should also be there,
even though it is redundant.

2. Same question for Test.cpp. Should #include <vector> be there since
it already comes from #include Funcs.h?

Thank you,
Joe

Victor Bazarov

unread,
Mar 25, 2015, 11:48:43 AM3/25/15
to
Every translation unit should include all headers that it needs to be
understood when read by a human being. Imagine that instead of the
standard container you would use some custom one, from some other
library. I think that in that case you would need to include the header
that defines that class/template. Same should apply to all standard
headers, I believe.

> 2. Same question for Test.cpp. Should #include <vector> be there since
> it already comes from #include Funcs.h?

Yes. Same reason as before.

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

Öö Tiib

unread,
Mar 25, 2015, 12:19:57 PM3/25/15
to
Well ... technically '#include "something.whatever"' means just that
preprocessor takes a text file nimed "something.whatever" and pastes
its contents to that spot. Meaning of '#include <vector>' is often same
in practice but not by C++ standard! By C++ standard '#include <vector>'
means that the interface of <vector> is included. Standard template
'std::vector', its specialization 'std::vector<bool>' and 'std::begin' and
'std::end' become known for compiler and useful for programmer.
Text file named "vector" isn't actually required to be existent.

If we build our own include files with the same policy as those standard
headers are built then the copy-paste include files become actually
interfaces. So "Funcs.h" is interface file for module 'Funcs'. "Funcs.cpp"
is implementation file for module 'Funcs'. Also it is good policy to
include interface header as first thing to module implementation
header.

Now what becomes '#include <vector>' in "Funcs.h" by that policy? It is
up to you.
1) You may say that '<vector>' will be always guaranteed to be
imported by 'Funcs' and so it is part of it. Then it is part of interface.
2) You may say that 'Funcs' will deal with a container of 'double's named
'Doubles' and 'Doubles' now being 'typedef std::vector<double>' Doubles;'
is implementation detail. Users still have to use 'Doubles' since it may
switch (even depending upon platform) to 'std::unordered_multiset<double>'
or 'boost::container::flat_multiset<double>' in future. Then it isn't part of
interface but there is guaranteed some container of doubles in it.
3) You may say that right now 'Funcs' deals only with vectors of doubles but
is planned to evolve into container-agnostic header-only template module
where 'sum' is something like:

namespace func
{
template<Container>
Container::value_type sum(Container const& container)
{
typedef Container::value_type Element;
Element sum {Element()};

for (Element const &e : container)
{
sum += e;
}

return sum;
}
} // func namespace

On such case you may say that <vector> is not part of interface and the
users should pick only vector of doubles now but may pick any container
themselves in the future.
4) Etc. Basically, you are the architect you tell.

> 2. Same question for Test.cpp. Should #include <vector> be there since
> it already comes from #include Funcs.h?

Same question and same answer. ;-) C++ does not contain real modules.
there were talks to add those to C++17. Since there are also "concepts
lite" and "reflection" in queue it is more likely that there either won't be
standard by 2017 or it won't contain modules.

So right now you have to emulate modules with policies of preprocessor
usage. What interfaces your "module" imports and what of those it
exposes is right now a meta-information that you have to deliver to your
module's users with comments, documentation or other external means.


Charles J. Daniels

unread,
Mar 25, 2015, 7:36:00 PM3/25/15
to
I am not aware of any best practices that may exist in this regard. Personally, if an include is in the header I purposely don't put it in the cpp file. It obviously serves no purpose to the code, so only possibly to the coder -- and in my case it's useless duplicate lines -- when I end up "removing" the header in the future, I may end up still including it anyway, is my mental perspective. Of course, if a communal project had a standard, I would go with that when participating.

Richard

unread,
Mar 31, 2015, 6:11:37 PM3/31/15
to
[Please do not mail me a copy of your followup]

Joseph Hesse <jo...@gmail.com> spake the secret code
<L9adnbgztbq-IY_I...@giganews.com> thusly:

>1. In Funcs.cpp the file Funcs.h was included since it seems like best
>practices for an X.cpp to always include an X.h.

Historically, the linking model in C/C++ is such that if you reference a
symbol in a translation unit, the entire translation unit's object code
is added to your executable. This is a simplistic linkage model, but
explains why you see a function like strcmp implemented in its own
translation unit when you look at historical sources for the C
standard library. Each translation unit was considered a "module".
Symbols with static linkage weren't visible outside the module, but
symbols with extern linkage were visible to consumers of the module.

I haven't investigated, but I imagine that modern linkers look for dead
code that isn't referenced by anything else and eliminate it from the
final executable. That may only be performed in certain optimization
modes (whole program optimization?) and may not happen in a debug build.

In this sort of scenario it was common to have a single header file
for the library (think <stdio.h>) that was included by every module in
the library. In this case, the header files and source files didn't
have a one-to-one mapping. Libraries are composed of one or more
modules and declarations are made visible to clients with one or more
header files. (The C standard library contains more than just
<stdio.h> for instance.)

C++ has better means controlling visibility of symbols: namespaces,
visibility specifiers within a struct/class/union, etc. In a C++ code
base it is more common to break things up into small classes and
compose libraries as a collection of classes. It is fairly common to
have a one-to-one mapping between source files and headers in that a
single source file implements a single (small) class and the class is
declared for consumers in a single header file. There may be a
convenience header file for a library that aggregate multiple header
files together. (This is quite common in boost libraries.)

>However one could
>argue that someone reading Funcs.cpp would see the use of the type
>vector<double> and therefore #include <vector> should also be there,
>even though it is redundant.

The general advice is that a header file should include everything
else needed for the declarations to compile. Therefore if you
reference std::vector<T> in some way in the header, you should include
<vector> in your header and not force the client to include <vector>
before including your header.

Further, if a source file uses something like std::vector, it should
include <vector>. The question in your example is whether or not
<vector> should appear in the header or just in the source file. If
you don't include <vector> in the header, then anyone who uses your
header must include <vector> *before* your header in order to use it.
This is placing a tax on users of Funcs.h that they must maintain. If
Funcs.h is later refactored to use some other container, or perhaps
not to use a container at all, then users of Funcs.h might be
including <vector> for no reason at all anymore. This is putting the
burden of maintenance in the wrong place. Include (or better, forward
declare) everything needed by your header file so that it stands
alone.

Some people write little test files in their build that look like this:

// TestFuncsHeader.cpp
#include "Funcs.h"

Their build system verifies that the header does indeed stand alone and
doesn't need any special magic in order to be used in isolation.

The philosophy behind the "include what you use" utility says that you
should include headers for everything you use in your source file:
<https://code.google.com/p/include-what-you-use/>

Their rationale for why you should do this is on their wiki:
<https://code.google.com/p/include-what-you-use/wiki/WhyIWYU>

So in this case, <vector> belongs in Funcs.h and is redundant in its
companion implementation file Funcs.cpp

>2. Same question for Test.cpp. Should #include <vector> be there since
>it already comes from #include Funcs.h?

If the only reason std::vector is used in Test.cpp is from the
callsites to code in Funcs.h, then I'd say no. When Test.cpp is
designed to test the implementation in Funcs.cpp, this is the clear
'no' case.

When a source file consumes functionality from Funcs.h, but also has
it's own code that uses std::vector outside of the API of Funcs.h,
then I would include <vector> in the source file. Eventually the
stuff using Funcs.h may split off this source file or switch to use
another API (or version of Funcs.h) that doesn't use std::vector, but
the source file still has its own need for std::vector. Then you want
to include <vector> in that source file, even though Funcs.h included
it already.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
0 new messages