Why do you need inclusion guard for C++ header files?

Viewed 253

I get roughly what it does. What I don't understand is why it's not the default? What are the use cases where some header file would need to be included multiple times?

4 Answers

The reason it's not the default is primarily historical these days -- when the C language was formalized, #include was specified that it must act exactly as if the user had copy-and-pasted the specified file's contents at the location of the #include-line; and C++ wanted (and wants) to remain as compatible as possible with C, so C++ inherited that behavior from C.

As for a use-case where including the same header file more than once might be useful; one instance where I found it useful was for simulating a templated-container-class in C (because C doesn't support templates directly). I had a container-implementation-header-file that looked something like this (but more elaborate; I'm showing a simplified version here for readability):

// MyContainerImplemention.h
// be sure to #define MYTYPE and MYARRAYSIZE
// before #include-ing this file!

struct ArrayOf##MYTYPE
{
   MYTYPE arrayOfItems[MYARRAYSIZE];
};

inline void Set##MYTYPE##Item(struct ArrayOf##MyType * container, int which, MYTYPE item) 
{
   container[which] = item;
}

[... and so on for various other MYTYPE-specific methods ...]

... then my .c files could do something like:

#define MYTYPE int
#define MYARRAYSIZE 10
#include "MyContainerImplementation.h"
#undef MYARRAYSIZE
#undef MYTYPE

#define MYTYPE short
#define MYARRAYSIZE 15
#include "MyContainerImplementation.h"
#undef MYARRAYSIZE
#undef MYTYPE

struct ArrayOfint myInts;
struct ArrayOfshort myShorts;

SetintItem(&myInts, 5, 12);
SetshortItem(&myShorts, 3, 2);
[...]

... and end up with the container "class" and its associated methods implemented for each data-type, without having to manually write a new implementation of the container "class" each time.

Yes, it was extremely ugly -- but not as ugly as having to manually write out thousands of lines of redundant container-code would have been. (The real container-implementation-header-file implemented a hash table and was several hundred lines long)

Without include guards or #pragma once the compiler would have to maintain a list of included files. This is not easy, because of different possible paths to these files (and #pragma once doesn't completely solve this) and would be expecting a bit much of the original C compilers, which had to work with very limited memory.

What's true today is not necessarily true when C came about and the C pre-processor, upon which the C++ one is based, was created.

#pragma once is just a step towards having proper C++ modules so this annoying historical legacy is finally eliminated.

Yes, it's valid to include a file multiple times, and yes, each time it's included it can behave in entirely different ways. This is why making pre-compiled headers is a huge headache for compiler developers.

Guard blocks or #pragma once are included in order to prevent a file from being included multiple times.

#pragma once, while supported on most compilers, is not an official part of the c++ standard, and may not work on every compiler. You can use a guard block, which will work on any compiler. An example of a guard block in the file MyClass.hpp would be:

#ifndef MYCLASS_HPP
#define MYCLASS_HPP

//Code here

#endif
Related