Site icon Embarcadero RAD Studio, Delphi, & C++Builder Blogs

C++ Builder Header Dependencies

Why should you care about header dependencies in C++?  One reason is header dependencies can have an impact on building, refactoring, testing and on the structure of your software.

And reducing header dependencies in C++ also reduces compile time dependencies – the dependencies between files and libraries at compile time.

One way to reduce header dependencies in C++ is to avoid including headers inside other header files.

Keeping header file dependencies to a minimum in C++ is always a good practice.  One topic in John Lakos’s Large Scale C++ Design book discusses reducing header dependencies in C++.  There is a rule written in “The Elements of Style”, “Omit needless words”. We can apply a similar rule here, “Omit needless headers“.
C++ Builder includes a Header Dependency view that’s useful for reducing dependencies:
That is particularly useful for Standard Template Library  (STL) headers.
For example, using this Averages header file (Averages.h), which declares a class Averages for averaging integers:

 

  

 

It’s a simple enough example to follow. Applications use this class via the Add(int) method, then calculate the average through GetAverage(). And for STL use, there is also a Add() method accepting a std::list of integers too, for example:  std::list nums1 {98, 95, 88, 90, 92, 89};
So what’s wrong with this code?  Well, in many reasons, nothing. Like Lakos recommends, the header file is self-contained — it will compile by itself as it includes the header. So how can we improve this code?

In C++ Builder, Project Options | Project Properties, select Show Header dependencies in project manager and also select Index files for “Definitions and References’ :

Then in the C++ Code Editor, | right-click an identifier | Find > Header Dependency

Note:  This command is available only for 64-bit Windows, iOS, and Android target platforms.

 This command searches the entire active project for the header dependencies. It opens the Header Dependency pane, which contains the following information:

Using the C++ Builder Header Dependency, for the above Averages.h header file we get this:

The Header Dependency info is embedded in the object file (WIN32), or is an external .d file for other target platforms. (See here). 

The IDE views on these links header dependencies view and Header Dependency Results read the information from the object file, or the .d file directly. The information from the object can be dumped using tdump. The .d is a plain text file with a standard format.

From the Header Dependency View, we see many dependencies for the one #include <list> .  The first item is the original header, and the rest is what <list> brings in.
So, this tells us any code needing to call Add(const std::list&) includes “Averages.h” and gets included. And that’s OK.
But what about code that just wants to use the simpler add method Add(int)? They don’t need <list> but are forced to use it along with all its dependencies, and the cost of parsing and compiling the unused std::list code.
A common technique to resolve this kind of issue is by forward declaration, where you just declare the class needed in-place, and don’t define it. A forward declaration of a function or class simply introduces a name. According to Wikipedia: A forward declaration is a declaration of an identifier for which the programmer has not yet given a complete definition. This can be used in situations where you need to know that the name of a class is a type, but not necessarily the structure. In C++, classes can be forward-declared if you only need to use the pointer-to-that class type or reference, since all pointers and references are the same size and can have the same operations performed on them.  In C++, you get the declaration of a function by including its header file, which can be put in either a .cpp file or a header file. When you include a header in another header file, you may be slowing down compilation time because you may be including other files unnecessarily, as we see in the C++ Builder Header Dependency view!
Since C++ allows you to refer to a declared (but not defined) class as long as you don’t try and find its size, or call any functions within it. This means we don’t need the #include after all:
Instead, we can have a SimpleAverages.h like this:
We used a forward declaration so that the compiler would know what “add” was when compiling main.cpp. Writing forward declarations for every function you want to use that lives in another file can get repetitive quickly.  The compiler wants to ensure you haven’t made spelling mistakes or passed the wrong number of arguments to the function. So, the compiler insists that it first sees a declaration of ‘add’ (or any other types, classes or functions) before it is used.
But this won’t work for std::list since it’s an STL class, it is not just templated on the type that it holds. 
So the compiler will throw a Clang error like:  implicit instantiation of undefined template ‘std::list’  SimpleAverages.h: template is declared here.
It also has an allocator parameter which controls how the memory needed is allocated. This second parameter is defaulted to allocator, and forward declaring this gets more and more complex. And std::list is not as simply defined as even that. 
In C++ Builder, Lists are another commonly used portion of the STL. The list template class is an encapsulation of the commonly used linked list algorithm. The differences between STL lists and a standard linked list that a programmer might implement are twofold:
  1. The list type is ready made and thoroughly tested.
  2. An STL list will work with virtually any class you choose to place in it.

Does this mean that forward declaration isn’t possible with std::list ?

One workaround is if we define our own non-templated list class and uses that instead, we wouldn’t have these issues with predeclaration. But implementing our own list class isn’t easy, and we don’t get all the benefits of std::list‘s implementation. But we can use something like this, in CustomList.h:

And then we can create a NewAverages.h, like this:

Now we have the situation where clients of the Averagers class who use the std::list function must include the “CustomList.h”header, and have the dependencies and compile time of  #include <list>. 

However, if the client just needs the single integer Add(int), then they just include “NewAverages.h” and don’t get anything from <list>. While this isn’t the traditional façade mentioned in the GoF’s book, the name “façade” seems too good a fit, so that’s what we’ll call this technique.
It is a common practice of C++ Programmers to break up the code in multiple implementation files (usually extension with .c, .cxx, .cpp, etc.), and definition files (usually extension with .h, .hxx, .hpp, etc.). But, it is the responsibility of the C++ Builder preprocessor to make the contents of all the required definition files available in the implementation file before compilation.
We used to do this because we wanted to reduce the compilation time during the development as well as reuse the code written in different files. For example, if we want to develop a project, which has 10,000 lines of code, now during the development of the project or after it if we change any single line, then the compiler has to recompile all the 10,000 lines. In today’s computers, this might not be a big problem, but it could eventually become a compile time issue when projects become larger and larger. On the other hand, if we split our project into more than one file, such as 10 files each contain roughly 1000 lines, then any change in one file ideally should not affect the other files. It is very common in large-scale projects to have some general-purpose classes, which are useful in other projects too. So the natural solution to use those classes in other projects is to make the classes in separate files.
One drawback of this approach is that in order to use any constructors of the base class you need to explicitly re-implement them (usually just passing parameters through to the base implementation) in your façade class.
But how much difference does this really make? Of course, this depends on your code and its other dependencies, but if we have a cpp client that uses the std::list functionality, and another cpp client that just uses Add(int), we should see reduced compile times for the Add(int) client versus the client using the std::list functionality!
With C and C++ development, it’s easy for #includes to get out of hand, leaving you with a confusing number of header files and increasing compile times, so it’s nice to know that C++ Builder includes a Header Dependency view that’s useful for reducing dependencies, which will reduce compile times!
 
[DownloadButton Product=’Cbuilder’ Caption=’Start Your C++Builder FREE Trial Today’]
 
 
Exit mobile version