Best Practices for Use of C++ Header Files

Header files and include best practice

You should include all necessary files in every file that needs them. If MyProgram.cpp needs string, include it, instead of relying on it being included by Bar.hpp. There's no guarantee 2 weeks from now Bar.hpp will still include it, and then you'll be left with compiler errors.

Note the necessary - i.e. make sure you actually need an include, when a forward declaration or even leaving it out completely will do.

Also, note that some system headers might include others - apart from a few exceptions, there's no requirement. So if you need both <iostream> and <string> include both, even if you can compile only with one of them.

The order in which the includes appear (system includes vs user includes) is up to the coding standard you follow - consistency is more important than the choice itself.

include header file in this way, is this a good practice?

This is a decent and somewhat traditional way to use #include, if the array contents you're including has been automatically generated by some other process. (There are other ways of doing it, though, as I'll mention below.)

It is a classic tradeoff. Most of the time, a good rule that's worth following is that you should use the preprocessor only in straightforward, traditional ways, because when you start getting "tricky" it's all too easy to create an unholy mess.

But sometimes, you have an array whose contents you really want to generate using some automatic, external process. Copying and pasting the array definition into your source file would be tedious and error-prone, and you might have to keep redoing it as the array needed updating. Figuring out a way to automate the process is worth doing, and might even be worth violating the "no tricky preprocessor abuse" rule.

To make this work you will usually want to have some automatic process (perhaps an awk, sed, perl, or python script) that generates the included file with the correct syntax. If you're using make or something like it, you can have that step automatically performed whenever the actual source data for the array changes. For instance, in the example you gave, you might have an original "source file" tags.list containing lines like

html
head
title

and then in your Makefile use something like sed 's/.*/"&",' to create the include file with the proper string initializer syntax. That way you don't force the folks who are updating the list to remember to always use the right quotes and commas.

Also, as other commentators have suggested, you should probably give the file a name ending in something other than .h, to make clear that it's not an ordinary header file containing complete, valid C declarations. Better possibilities in this case would be .tab, .inc, or .arr.

With a little more work, though, you could avoid the "hack" and do things just about 100% conventionally. If you tweaked your script to add the line const char* kGumboTagNames[] = { at the beginning of the generated file, and }; at the end, you could give it a name ending in .c, and just compile it, rather than including it. (This approach, however, would involve its own tradeoff, in that it would constrain the array to being global, not static or local.)

Footnote: In some languages -- and even in C and C++, under some circumstances -- the comma is used as a separator, and you're not allowed to have one after the last element of a list. But in array initializers, you are allowed to have that trailing comma, and it turns out to be a pretty nice and useful freedom, precisely because it allows you to use straightforward techniques like the one described here, without the nuisance of having to insert an explicit extra step to get rid of the comma after the last element in the list.

Best practices: c++ header includes

1.I find it very annoying to include (for example) in every class I want to use a vector. Is there a better way?

Imagine how annoying it is for others who use your code (and that other could be your future self) and get a compilation error because there is a missing header for <vector>. Write it once, use it many times over.

2.I've got a good bit of core functionality (also in it's separate namespace) with quite a few classes that doesn't change often. While I
don't need all the functionality in every class, it would be very nice
to just have one single header file, include that and be done with
it... What's the best way to do this?

You can do this for speedup, if you let your IDE include this automatically as a precompiled-header. But for correctness and portability alone you should not rely on it and always let every header be compilable as a standalone header. See e.g. Item 23 in Alexandrescu & Sutter's Coding Standard. Build systems like CMake even have macros to test for this.

3.Is it bad practice to include headers in a precompiled header file? If yes, why?

You can do it, but it's best to let the IDE do this in order to get better portability. And those headers better be stable (the Standard Library or Boost e.g., but never your own project headers).

Is it good practice to always include the standard headers?

Best practice is for each source file, whether it is a .c file or .h file, to include only the headers it needs. Doing so not only reduces compilation time but also serves to document the file's functionality.

Here are a few examples:

f1.c:

#include <stdio.h>

void print_int(int i)
{
printf("i=%d\n", i);
}

f2.c:

#include <stdlib.h>

void *safe_malloc(size_t size)
{
void *p = malloc(size);
if (!p) exit(1);
return p;
}

f3.c:

int sum(int a, int b)
{
return a+b;
}

The file f1.c only includes stdio.h because it does I/O but no other functions. Similarly, f2.c only includes stdlib.h because it uses functions defined there but does not use any I/O function, and f3.c doesn't include any headers because it doesn't need them.

If you think you've included unnecessary files, comment them out and compile with all warnings enabled to see which ones declare functions or variables you need.

C Header Files - Good Practice

You normally distinguish between source and header files in the same way that Objective-C differentiates between implementation (.m) and interface (.h) files. Source files contain everything that may execute, header files contain enough information about symbols that other source files know how to communicate with that source file.

Header files often include other header files, so you'll see #include in both source and implementation files. #include operates exactly like #import except that it doesn't automatically check whether you've #included the same file twice. So C header files often look something like:

#ifndef __SOME_SYMBOL
#define __SOME_SYMBOL

... rest of header file here ...

#endif

Which has the same effect of ensuring the main body of the header file is included only once.

EDIT: more on this, as per request. Obviously you'd never do something like:

#include "File.h"
#include "File.h"

But you can easily end up with something like:

#include "FirstComplexThing.h"
#include "SecondComplexThing.h"

Where both FirstComplexThing.h and SecondComplexThing.h rely on something inside and hence #include SimpleThing.h. So you end up with SimpleThing.h #included twice, without making any sort of error or following any bad design pattern.

C compilers work just like Objective-C compilers — each source file is compiled on its own, in isolation, with no overview until the linker comes along. #include is a preprocessor directive that has the same logical effect as copying the contents of the named file and pasting them into your source file at that location, so if you end up the same file #included twice you'll probably end up with something like:

char *somePointer; // I'm from SimpleThing.h

... lots of other things ...

char *somePointer; // I'm from SimpleThing.h

And the compiler will stop with an error that the same thing is declared twice. #import in Objective-C avoids that by being shorthand for '#include, but only if you haven't already #included that file'. The C #ifndef/#define/#endif convention achieves the same thing as #import because the #ifndef/#endif pair say that the stuff in between should be passed on to the compiler if the nominated preprocessor symbol (__SOME_SYMBOL in my example; it tends to be a name derived from the name of that header file but exact conventions vary) hasn't been defined. It won't have been the first time the construct is encountered. Because it is defined inside the construct, it will have been when the same #ifndef is encountered the second time, so the stuff up to the matching #endif won't be passed on.

Although it's a question of style, it is very often the case that each C file has one H file that is directly connected to it.

There are no classes in C, obviously, but if you mean a construct like:

@class SomeClass;

@interface SomeOtherClass: NSObject
{
SomeClass *otherClass; // I can reference SomeClass without importing
// the interface file because I've declared the
// type above
}

- (void)whatever;
@end

That's actually the normal C distinction between declarations and definitions. You'll have a problem if you do something like:

struct SomeStruct;

struct SomeOtherStruct
{
struct SomeStruct otherStruct;
};

Because the compiler doesn't have enough information. It doesn't know how large SomeStruct should be, so it can't work out how SomeOtherStruct should be laid out. However, this is completely valid:

struct SomeStruct;

struct SomeOtherStruct
{
struct SomeStruct *otherStruct;
};

Because the size of a pointer is always known, irrespective of what it is pointing to. You'll often see that C libraries with opaque types describe those types by pointer only (sometimes to void *, but not always — e.g. stdio.h uses FILE *) or just give you an integer (including OpenGL, notably). So they ensure you've something that the compiler will know the size of without having to tell you what data they're associating with it or giving you any way to try to manipulate it yourself.

It's perfectly good practice to put pointers in the header file (assuming it's good practice to expose the thing globally, obviously). The same thing is often done in Objective-C, albeit for slightly different reasons, e.g.

// interface/header file

extern NSString *someGlobalIdentifier;

And:

// implementation/source file

NSString *someGlobalIdentifier = @"somethingOrOther";

In Objective-C that's because you can then test identity rather than always having to test equality, but basically the same rules apply to C with respect to it being normal to put the reference (be it a pointer or whatever) that represents a thing into the header and create or declare the thing in a source file. In fact, if you start putting declarations in the header file you'll end up with errors when the program comes to link because multiple source files will think they declare the thing.

Best practice for using includes in C

Don't use includes, you don't need.

I'd choose something like "Option 1". Why "something like" ? Because I'd create a separate file for the main and I'd keep all declaraions inside the .h and all definitions inside the corresponding .c.

Of course, both options are valid.

If you want to include only one header in your main, you can just create a header file, containing only includes - that's a common practice. This way, you can include only one header, instead of several.

Is it a good practice to place C++ definitions in header files?

Your coworker is wrong, the common way is and always has been to put code in .cpp files (or whatever extension you like) and declarations in headers.

There is occasionally some merit to putting code in the header, this can allow more clever inlining by the compiler. But at the same time, it can destroy your compile times since all code has to be processed every time it is included by the compiler.

Finally, it is often annoying to have circular object relationships (sometimes desired) when all the code is the headers.

Bottom line, you were right, he is wrong.

EDIT: I have been thinking about your question. There is one case where what he says is true. templates. Many newer "modern" libraries such as boost make heavy use of templates and often are "header only." However, this should only be done when dealing with templates as it is the only way to do it when dealing with them.

EDIT: Some people would like a little more clarification, here's some thoughts on the downsides to writing "header only" code:

If you search around, you will see quite a lot of people trying to find a way to reduce compile times when dealing with boost. For example: How to reduce compilation times with Boost Asio, which is seeing a 14s compile of a single 1K file with boost included. 14s may not seem to be "exploding", but it is certainly a lot longer than typical and can add up quite quickly when dealing with a large project. Header only libraries do affect compile times in a quite measurable way. We just tolerate it because boost is so useful.

Additionally, there are many things which cannot be done in headers only (even boost has libraries you need to link to for certain parts such as threads, filesystem, etc). A Primary example is that you cannot have simple global objects in header only libs (unless you resort to the abomination that is a singleton) as you will run into multiple definition errors. NOTE: C++17's inline variables will make this particular example doable in the future.

As a final point, when using boost as an example of header only code, a huge detail often gets missed.

Boost is library, not user level code. so it doesn't change that often. In user code, if you put everything in headers, every little change will cause you to have to recompile the entire project. That's a monumental waste of time (and is not the case for libraries that don't change from compile to compile). When you split things between header/source and better yet, use forward declarations to reduce includes, you can save hours of recompiling when added up across a day.

Header Files in Multiple Directories: Best Practices

For test_foo.c you simply need to tell the compiler where the header files can be found. E.g.

gcc -I../src -c test_foo.c

Then the compiler will also look into this directory to find the header files. In test_foo.c you write then:

#include "foo.h"

EDIT:
To link against foo.c, actually against foo.o, you need to mention it in the object file list. I assume you have already the object files, then do after that:

gcc test_foo.o ../src/foo.o -o test


Related Topics



Leave a reply



Submit