Mir C++ Style Guide

Revision 4.2

Tim Penhey
Neil J. Patel
Thomas Voss

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
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. Click it 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.

Style, also known as readability, is what we call the conventions that govern our C++ code. The term Style is a bit of a misnomer, since these conventions cover far more than just source file formatting.

One way in which we keep the code base manageable is by enforcing consistency. It is very important that any programmer be able to look at another's code and quickly understand it. Maintaining a uniform style and following conventions means that we can more easily use "pattern-matching" to infer what various symbols are and what invariants are true about them. Creating common, required idioms and patterns makes code much easier to understand. In some cases there might be good arguments for changing certain style rules, but we nonetheless keep things as they are in order to preserve consistency.

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 .cpp file should have an associated .h file. There are some common exceptions, such as unit tests and small .cpp 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_.

Header File Dependencies

link
Don't use an #include when a forward declaration would suffice.

Inline Functions

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

The -inl.h Files

link
You may use file names with a -inl.h suffix to define complex inline functions when needed.

Function Parameter Ordering

link
When defining a function, parameter order is: outputs, then inputs.

Names and Order of Includes

link
Use standard order for readability and to avoid hidden dependencies: your project's public .h, your project's private .h, other libraries' .h, .C library, C++ library,

Scoping

Namespaces

link
Unnamed namespaces in .cpp files are encouraged. With named namespaces, choose the name based on the project, and possibly its path. Do not use a using-directive in a header file.

Nested Classes

link
Although you may use public nested classes when they are part of an interface, consider a namespace to keep declarations out of the global scope.

Nonmember, Static Member, and Global Functions

link
Prefer nonmember functions within a namespace or static member functions to global functions; use completely global functions rarely.

Local Variables

link
Place a function's variables in the narrowest scope possible, and initialize variables in the declaration.

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.

Constructors

link
The purpose of a constructor is to initialise a class so that its invariants hold. For value classes it is worth having a cheap default constructor.

Default Constructors

link
You must define a default constructor if your class defines member variables of POD types and has no other constructors. Otherwise the compiler will do it for you, badly.

Explicit Constructors

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

Copy Constructors

link
Provide a copy constructor and assignment operator only when necessary. Otherwise, disable them with the help of = delete;.

Structs vs. Classes

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

Inheritance

link
Composition is often more appropriate than inheritance. When using inheritance, make it public.

Multiple Inheritance

link
Only very rarely is multiple inheritance of implementation actually useful. We allow multiple inheritance only when at most one of the base classes has an implementation; all other base classes must be interface classes.

Interfaces

link
Classes that satisfy certain conditions are interfaces.