Is there a case where including the same header twice is really useful?

Creating header protectors for h / hpp files has always been my usual practice, but I wonder why you can even include the same file twice? Is there a case when you really need insecure headers?

+7
source share
6 answers

Files with "Parameterized" parameters can be used to simulate C ++ - ish templates in style C. In such cases, the header file will depend on the number of macros ("template parameters"). It will generate different code depending on the actual "value" of these macros.

Thus, a typical use of such a header would look like a sequence of macro definitions “template”, followed by a directive #include , followed by another sequence of macro definitions “template parameter”, followed by the same #include , etc.

stack overflow

When using this method, you will see header files without any security devices or header files with security devices enabled that cover only part of the file.

+8
source

Things like Boost.PP do a lot of tricks, including headings several times. It essentially allows for primitive loop shapes.

In addition, X-Macros are designed to be turned on several times.

+6
source

In C:

 #undef NDEBUG #include <assert.h> ...code using active asserts... #define NDEBUG #include <assert.h> ...code using disabled asserts... 

Rinse and repeat. An analog in C ++ uses the <cassert> header <cassert> .

So, sometimes there are reasons to include the title twice. Not often, but there are reasons for this.

+6
source

Cases like these are rare, and when they exist, redesign is best suited in any case. One of them that I can think of is headings that contain declarations:

 //functions.h virtual void foo(); virtual void goo(); //classes.h class A : public Base { #include "functions.h" }; class B : public Base { #include "functions.h" }; 

This will not work if functions.h enabled the guards, but again, this is a rather inconvenient code ...

+1
source

Imagine that you are writing your own wrapper for an array of templates (pointers) for your small engine, where the array can be:

  • dynamic or static
  • indexes / order matter or not
  • you can remove an element (and not just delete from the array) outside the array or inside

therefore, with this you can either create one class where all this is processed, but it will always check what we can or cannot do. it is best to create separate classes, but here we have the same code between them that you could (if not carefully) either make an error in one of them or add a new function would be slower.

it is best to use header files with parameters (as indicated by AnT) and just create classes like

  • Cl_Array_Dy, Cl_Array_DyIn, Cl_Array_DyDel, Cl_Array_DyInDel
  • Cl_Array_St, Cl_Array_StIn, Cl_Array_StDel, Cl_Array_StInDel
Code example

:

//TestDfM.h

 #ifndef TEST_DFM_H # define TEST_DFM_H // first we need to make sure neither of these is defined # ifdef Df_ARG1 # undef Df_ARG1 # endif # ifdef Cl_First # undef Cl_First # endif # ifdef Cl_Second # undef Cl_Second # endif # ifdef Df_FIRST # undef Df_FIRST # endif # ifdef Df_SECOND # undef Df_SECOND # endif # ifdef TEST_DF_H # undef TEST_DF_H # endif // we need this # define Df_FIRST 1 # define Df_SECOND 2 // first class creation # define Df_CLASS Df_FIRST # define Df_ARRAY Cl_First # include "TestDf.h" // cleanup (after 1st) # undef Df_CLASS # undef Df_ARRAY // second class creation # define Df_CLASS Df_SECOND # define Df_ARRAY Cl_Second # define Df_ARG1 # include "TestDf.h" // cleanup (after 2st) # undef Df_CLASS # undef Df_ARRAY # undef Df_ARG1 // so we theoretically cannot include TestDf.h anymore (anywhere) # define TEST_DF_H #endif // TEST_DFM_H 

//TestDf.h

 // nothing to do here if the main header for this was not included // also we should only call this inside the main header #if defined(TEST_DFM_H) && !defined(TEST_DF_H) # include "../Includes.h" class Df_ARRAY { public: int m_shared; # ifndef Df_ARG1 Df_ARRAY(int in_shared=0) { m_shared= in_shared; } void f_info() { printf("out: %d\n", m_shared); } # else int m_x; Df_ARRAY(int in_shared=0, int in_x= 7) { m_shared= in_shared; m_x= in_x; } void f_info() { printf("out: %d [also has %d]\n", m_shared, m_x); } # endif # if Df_CLASS == Df_FIRST void f_class() { printf("1st\n"); } # elif Df_CLASS == Df_SECOND void f_class() { printf("2nd\n"); } # endif }; #endif // TEST_DFM_H 

//Main.cpp

 #include "Array/TestDfM.h" int main(int argc, char** argv) { Cl_First a(6); Cl_Second b(2); a.f_class(); // 1st b.f_class(); // 2nd a.f_info(); // out: 6 b.f_info(); // out: 2 [also has 7] return 0; } 
+1
source

Header files are only text included when they occur. There is no real reason why they cannot be turned on more than once. If headers are used only for declaration and without definitions (and without template declarations with default arguments), there is not even a problem with including them more than once.

Thus, <cassert> is a canonical example of including a file more than once: you can change the NDEBUG definition and get different behavior from the assert() macro within the same translation unit.

Now, something like include_once , which includes a file only once, is not as trivial as people tend to think. Here is an example where it is not clear how often foo.h should be included:

 #include_once "foo.h" #include_once "./foo.h" #include_once "bar/foo.h" 

Assuming include_once includes each file only once, how often should foo.h be included? All three files can easily link to the same physical file, but it may not be easily visible, for example, because one of them is a link to the other. It seems best to give the programmer control over how you can control how often they end up being used.

0
source

All Articles