ALICE O² C++ Coding Guidelines

Vasco Barroso
Alina GrigoraȘ
Ivana Hřivnáčová
Matthias Kretz
Adriana Telesca
Barthélémy von Haller

This document is based on the work of
B. Weinberger, C. Silverstein,
G. Eitzmann, M. Mentovai
and T.Landray
at http://google-styleguide.googlecode.com,
C++ Google Style guide, Revision 3.274
under the CC-By 3.0 License

Each style point has a summary for which additional information is available by toggling the accompanying arrow button that looks this way: . You may toggle all summaries with the big arrow button:

Toggle all summaries
Toggle all extra details
Table of Contents

Important Note

Displaying Hidden Details in this Guide

link
This style guide contains many details that are initially hidden from view. They are marked by the triangle icon, which you see here on your left. The first level of hidden information is the subsection Summary in each rule and the second level of hidden information is the optional subsection Extra details and exceptions to the rule. Click the arrow on the left now, you should see "Hooray" appear below.

Background

As every C++ programmer knows, the language has many powerful features, but this power brings with it complexity, which in turn can make code more bug-prone and harder to read and maintain.

The goal of this guide is to manage this complexity by describing in detail the dos and don'ts of writing C++ code. These rules exist to keep the code base manageable while still allowing coders to use C++ language features productively.

Another issue this guide addresses is that of C++ feature bloat. C++ is a huge language with many advanced features. In some cases we constrain, or even ban, use of certain features. We do this to keep code simple and to avoid the various common errors and problems that these features can cause. This guide lists these features and explains why their use is restricted.

Note that this guide is not a C++ tutorial: we assume that the reader is familiar with the language.

Header Files

In general, every .cxx file should have an associated .h file. There are some common exceptions, such as unittests 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.

The #define Guard

link
All header files should have #define guards to prevent multiple inclusion. The format of the symbol name should be <PROJECT>_<PATH>_<FILE>_H_. Avoid using #pragma once.

Forward Declarations

link
You may forward declare ordinary classes in order to avoid unnecessary #includes.

Inline Functions

link
As a general rule, put function definitions into the .cxx file and let the compiler decide what gets inlined (it can decide anyway, regardless of the inline keyword). Use inline when you require the implementation of a function in multiple translation units (e.g. template classes/functions).

Names and Order of Includes

link
Include headers from external libraries using angle brackets. Include headers from your own project/libraries using double quotes.
Do not rely on implicit includes. Make header files self-sufficient.

Namespaces

Namespaces subdivide the global scope into distinct, named scopes, and thus are useful for logically grouping related types and functions and preventing name collisions.

General guideline

link
Use a namespace for the project, a second nested namespace for code inside a sub-project. Use one or two more nested namespaces to logically group types and functions together.

Using declarations and directives

link
Don't write namespace using declarations or using directives in a header file or before an #include.

Unnamed namespaces

link
Unnamed namespaces are allowed and even encouraged in .cxx files, they are not allowed in .h files.

Namespace aliases

link
Namespace aliases are allowed anywhere in a .cxx file, inside the named namespace that wraps an entire .h file and in functions and methods.

std namespace

link
Do not declare anything in namespace std, not even forward declarations of standard library classes.

Scoping

Nonmember and Global Functions

link
Nonmember functions (also known as global functions) should be within a namespace.

Local Variables

link
Declare variables as locally as possible.

Variables Initialization

link
Always initialize variables.
since C++11

Brace Initialization

link
Prefer initialization with braces except for single-argument assignment.

Global Variables

link
Variables declared in the global scope are not allowed. Other global variables, including static class variables and variables in namespace scope, should be avoided where other means of communication are possible.

Global variables initialization

link
In the rare and justified cases where you use global variables, including file-static variables, static member variables and variables in namespace scope, initialize them statically.

Static Variables in functions

link
Static variables in functions (called "function-local static variables" in the C++ terminology) are expensive and need care on destruction. Prefer to use static class variables where possible.

Classes

Classes are the fundamental unit of code in C++. Naturally, we use them extensively. This section lists the main dos and don'ts you should follow when writing a class.

Initialization

link
Declare and initialize members variables in the same order. Prefer initialization (in the constructor initializer list or in-class) to assignment (in the constructor function body). Do not perform unmanaged resource acquisition in the constructor.

Virtual functions in constructors and destructors

link
Do not call virtual functions in constructors and destructors.

Explicit Constructors

link
Use the C++ keyword explicit for constructors with one argument.

Copy (and Move)

link
Explicitly enable or disable the copy constructor/assignment operator. Only implement move constructors/assignment operators if your class needs optimizations for move semantics.
since C++11

Delegating and inheriting constructors

link
Use delegating and inheriting constructors when they reduce code duplication.

Structs vs. Classes

link
Use a struct only for passive objects that carry data; everything else is a class.

Destructors

link
Every class must free resources (objects, IO handlers, etc.) it allocated during its lifetime. The base class destructors must be declared virtual if they are public.

Inheritance

link
When using inheritance, make it public and declare overriden methods as override or final. However, composition is often more appropriate than inheritance especially if a class is not designed to be a base class.

Multiple Inheritance

link
Use multiple inheritance implementation only when at most one of the base classes has an implementation; all other base classes must be pure interface classes.

Interfaces

link
If a class was designed as a pure interface, keep it as a pure interface.

Operator Overloading

link
When overloading operators keep the same semantics.

Access Control

link
Hide internals. Avoid returning handles to internal data managed by your class.

Others

Exceptions

link
C++ exceptions can be used for error handling in non-performance-relevant code, like context initialization running only once during the lifetime of the program. Usually return values shall be used.

Use of const

link
Declare objects that are logically constant as const. Design const-correct interfaces. Consider constexpr for some uses of const.
since C++11

Use of constexpr

link
In C++11, use constexpr to define true constants or to ensure constant initialization.

Smart Pointers

link
std::unique_ptr and std::shared_ptr should be used consistently instead of non-owning raw pointers. Never use owning raw pointers, and thus never use delete. The use of raw pointers may need an explanation in form of a comment.

Magic numbers

link

Avoid magic numbers.

Preprocessor Macros

link
Avoid macros. Use inline functions, constexpr functions, enums, constexpr variables, or templates instead if they can solve the problem.

Write Short Functions

link
Prefer small and focused functions.

Run-Time Type Information (RTTI)

link
Avoid using Run Time Type Information (RTTI).

Casting

link
In general, avoid designs that require casting. You may use static_cast when necessary, but avoid const_cast and reinterpret_cast. C-casts are forbidden.

Variable-Length Arrays and alloca()

link
Don't use variable-length arrays or alloca().

Increment and Decrement operators

link
Prefer the prefix form of the increment (++i) and decrement (--i) operators because it has simpler semantics.

Loops and Switch Statements

link

If not conditional on an enumerated value, switch statements should always have a default case. Empty loop bodies should use {} or continue.

Integer Types

link
Per default, use int if you need an integer type. Prefer signed integers over unsigned integers and thus std::int64_t over unsigned int if you need more bits.

Portability

link
Take extra care of the code portability. Bear in mind problems of printing, comparisons, and structure alignment related to 32-bit and 64-bit data representations .

0 and nullptr

link
Use 0 for integers, nullptr for pointers, and '\0' for chars.

sizeof

link
Prefer sizeof(varname) to sizeof(type).
since C++11

auto

link
Use auto to avoid type names that are just clutter. Continue to use manifest type declarations when it helps readability, and never use auto for anything but local variables.

Exceptions to the Rules

The coding conventions described above have to be followed. However, like all good rules, these sometimes have exceptions.

Existing Non-conformant Code

link
It is permissible to deviate from the rules when dealing with code that does not conform to these guidelines.

Parting Words

Use common sense and BE CONSISTENT.

The point about having style guidelines is to have a common vocabulary of coding so people can concentrate on what the programmer is saying, rather than on how he/she is saying it.

OK, enough writing about writing code; the code itself is much more interesting. Have fun!

References

[1] Herb Sutter on software, hardware, and concurrency blog [http://herbsutter.com/2013/05/09/gotw-1-solution]