CbmRoot
Header files

In general, every .cxx file should have an associated .h file. There are some common exceptions, such as unit tests and small .cxx files containing just a main() function. Correct use of header files can make a huge difference to the readability, size and performance of your code. The following rules will guide you through the various pitfalls of using header files.

Self-contained Headers

Header files should be self-contained (compile on their own) and end in .h. Non-header files that are meant for inclusion should end in .inc and be used sparingly. All header files should be self-contained. Users and refactoring tools should not have to adhere to special conditions to include the header. Specifically, a header should have header guards and include all other headers it needs.

Prefer placing the definitions for template and inline functions in the same file as their declarations. The definitions of these constructs must be included into every .cxx file that uses them, or the program may fail to link in some build configurations. If declarations and definitions are in different files, including the former should transitively include the latter. Do not move these definitions to separately included header files (-inl.h); this practice was common in the past, but is no longer allowed.

As an exception, a template that is explicitly instantiated for all relevant sets of template arguments, or that is a private implementation detail of a class, is allowed to be defined in the one and only .cc file that instantiates the template.

There are rare cases where a file designed to be included is not self-contained. These are typically intended to be included at unusual locations, such as the middle of another file. They might not use header guards, and might not include their prerequisites. Name such files with the .inc extension. Use sparingly, and prefer self-contained headers when possible.

The #define Guard

All header files should have #define guards to prevent multiple inclusion.
The format of the symbol name should be

<CLASSNAME>_H

Since there should be no class with the same name this should guarantee uniqueness. For example, the file sim/detectors/much/qa/CbmMuchTransportQa.h should have the following guard:

#ifndef CBMMUCHTRANSPORTQA_H
#define CBMMUCHTRANSPORTQA_H
...
#endif // CBMMUCHTRANSPORTQA_H

Include Only What You Use

If a source or header file refers to a symbol defined elsewhere, the file should directly include a header file which properly intends to provide a declaration or definition of that symbol. It should not include header files for any other reason.

Do not rely on transitive inclusions. This allows people to remove no-longer-needed #include statements from their headers without breaking clients. This also applies to related headers - foo.cxx should include bar.h if it uses a symbol from it even if foo.h includes bar.h.

Forward Declarations

You may forward declare ordinary classes in order to avoid unnecessary #include statements.

A "forward declaration" is a declaration of a class, function, or template without an associated definition. #include lines can often be replaced with forward declarations of whatever symbols are actually used by the client code.

Pros:

  • Unnecessary #include statements force the compiler to open more files and process more input.
  • They can also force your code to be recompiled more often, due to changes in the header.

Cons:

  • It can be difficult to determine the correct form of a forward declaration in the presence of features like templates, typedefs, default parameters, and using declarations.
  • Forward declaring multiple symbols from a header can be more verbose than simply including the header.
  • Forward declarations of functions and templates can prevent the header owners from making otherwise-compatible changes to their APIs; for example, widening a parameter type, or adding a template parameter with a default value.
  • Forward declaring symbols from namespace std:: usually yields undefined behavior.

Decision:

  • When using a function declared in a header file, always #include that header.
  • When using a class template, prefer to #include the header file.
  • When using an ordinary class, relying on a forward declaration is OK, but be wary of situations where a forward declaration may be insufficient or incorrect; when in doubt, just #include the appropriate header.
  • Do not replace data members with pointers just to avoid an #include statement.

Always #include the file that actually provides the declarations/definitions you need; do not rely on the symbol being brought in transitively via headers not directly included.

Inline Functions

Define functions inline only when they are small, say, 10 lines or fewer.

Definition:

  • You can declare functions in a way that allows the compiler to expand them inline rather than calling them through the usual function call mechanism.

Pros:

  • Inlining a function can generate more efficient object code, as long as the inlined function is small. Feel free to inline accessors and mutators, and other short, performance-critical functions.

Cons:

  • Overuse of inlining can actually make programs slower. Depending on a function's size, inlining it can cause the code size to increase or decrease. Inlining a very small accessor function will usually decrease code size while inlining a very large function can dramatically increase code size. On modern processors smaller code usually runs faster due to better use of the instruction cache.

Decision:

  • A decent rule of thumb is to not inline a function if it is more than 10 lines long. Beware of destructors, which are often longer than they appear because of implicit member- and base-destructor calls!
  • Another useful rule of thumb: it's typically not cost effective to inline functions with loops or switch statements (unless, in the common case, the loop or switch statement is never executed).
  • It is important to know that functions are not always inlined even if they are declared as such; for example, virtual and recursive functions are not normally inlined. Usually recursive functions should not be inline. The main reason for making a virtual function inline is to place its definition in the class, either for convenience or to document its behavior, e.g., for accessors and mutators.

Names and Order of Includes

Headers should be included in an order from local to global. Separate each non-empty group with one blank line. This results in the following order:

  1. Header file corresponding to this cxx file.
  2. A blank line.
  3. Your project's header files.
  4. A blank line.
  5. Other libraries header files.
    1. FairRoot header files.
    2. A blank line.
    3. Root header files.
    4. A blank line.
    5. Boost and other external header files.
  6. A blank line.
  7. C++ standard library headers (without file extension), e.g., <algorithm>, <cstddef>.
  8. A blank line.
  9. C system headers (more precisely: headers in angle brackets with the .h extension), e.g., <unistd.h>, <stdlib.h>

All of a project's header files should be listed without the use of a directory.

Note that the C headers such as stddef.h are essentially interchangeable with their C++ counterparts (cstddef). Either style is acceptable, but prefer consistency with existing code.

Within each section the includes should be ordered alphabetically.

There are two types of #include statements: #include <myFile.h> and #include "myFile.h". The difference between both is the order of directory paths used to access the header files

Include headers from external libraries using angle brackets.

#include <FairRootManager.h>

Include headers from your own project/libraries using double quotes.

#include "CbmMuchDigi.h"

Using Directrives

Don't use using directives in header files.

CbmMuchDigi.h