C++ Style Guide

Revision 1.0

Krishna Kumar
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

C++ is the main development language for most of our projects. 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. One way in which we keep the code base manageable is by enforcing consistency .

Note that this guide is not a C++ tutorial.

Naming

The most important consistency rules are those that govern naming. The style of a name immediately informs us what sort of thing the named entity is: a type, a variable, a function, a constant, a macro, etc., without requiring us to search for the declaration of that entity.

Remember that a maintaining a consistent style is often more important than doing every little detail in the way you think best.

General Naming Rules

link
Function names, variable names, and filenames should be descriptive; eschew abbreviation.

File Names

link
Filenames should be all lowercase and can include underscores ( _ ). C++ files should end in .cc and header files should end in .h . Follow the conventions of your project.

Type Names

link
Type names start with a capital letter and have a capital letter for each new word, with no underscores: MpmParticleClass , MpmParticleEnum .

Variable Names

link
Variable names are all lowercase, with underscores between words. Class member variables have trailing underscores. For instance: local_variable , member_variable_ .

Function Names

link
Functions should be lower case; accessors and mutators match the name of the variable: particle_function() , particle_method() , member_variable() , set_member_variable() .

Namespace Names

link
Namespace names are all lower-case, and keep it meaningful mpm_material .

Macro Names

link
You're not really going to define a macro , are you?

Exceptions to Naming Rules

link
If you are naming something that is analogous to an existing C or C++ entity then you can follow the existing naming convention scheme.

Header Files

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

Forward Declarations

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

Inline Functions

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

The .tcc Files

link
You may use file extension .tcc for shared templatised classes.

Function Parameter Ordering

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

Names and Order of Includes

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

Scoping

Namespaces

link
Unnamed namespaces in .cc files are encouraged, especially when using static variables. With named namespaces, choose the name based on the project, and possibly its path. Do not use a using-directive . Do not use inline namespaces.

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.

Static and Global Variables

link
Static or global variables of class type are forbidden: they cause hard-to-find bugs due to indeterminate order of construction and destruction. However, such variables are allowed if they are constexpr : they have no dynamic initialization or destruction.

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.

Doing Work in Constructors

link
Avoid doing complex initialization in constructors (in particular, initialization that can fail or that requires virtual method calls).

Initialization

link
If your class defines member variables, you must provide an in-class initializer for every member variable or write a constructor (which can be a default constructor). If you do not declare any constructors yourself then the compiler will generate a default constructor for you, which may leave some fields uninitialized or initialized to inappropriate values.

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.

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 .

Inheritance

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

Multiple Inheritance

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

Abstract Base Class

link
Classes that provide an interface for creating families of related or dependent objects without specifying their concrete class.

Operator Overloading

link
Do not overload operators except in rare, special circumstances. Do not create user-defined literals.

Access Control

link
Make data members private , and provide access to them through accessor functions as needed. Use protected only when using it as a common data for implementers of the base class. Typically a variable would be called foo_ and the accessor function foo() . You may also want a mutator function set_foo() . Exception: static const data members need not be private .

Declaration Order

link
Use the specified order of declarations within a class: public: before private: , methods before data members (variables), etc.

Write Short Functions

link
Prefer small and focused functions.

Other C++ Features

Reference Arguments

link
All parameters passed by reference must be labeled const . Use a pointer to modify an object.

Function Overloading

link
Use overloaded functions (including constructors) only if a reader looking at a call site can get a good idea of what is happening without having to first figure out exactly which overload is being called.

Arrays

link
Do not use arrays , instead use std::vectors<T> .

Friends

link
Use friend classes and functions, within reason.

Exceptions

link
Use C++ exceptions, especially when parsing user inputs.

Casting

link
Casts are generally best avoided. In worst case, use C++ casts like static_cast<>() . Do not use other cast formats like int y = (int)x; or int y = int(x); .

Preincrement and Predecrement

link
Use prefix form ( ++i ) of the increment and decrement operators with iterators and other template objects.

Use of const

link
Use const whenever it makes sense. With C++11, constexpr is a better choice for some uses of const. More information about const correctness.

Use of constexpr

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

Integer Types

link
int is generally 32bits. If your variable represents a value that could ever be greater than or equal to 2^31, use a 64-bit type such as int64_t from <stdint.h> .

Preprocessor Macros

link
Never use Macros. Prefer inline functions, enums, and const variables to macros.

0 and nullptr/NULL

link
Use 0 for integers, 0.0 for reals, nullptr (or NULL ) for pointers, and '\0' for chars.

sizeof

link
Prefer sizeof( varname ) to sizeof( type ) .

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.

for loops

link
Use range based for loops and std::for_each when iterating through all the elements in a container, use these whenever possible. You can also use itertor based for loop.

Brace Initialization

link
You may use brace initialization.

Ownership and Smart Pointers

link
Prefer to have single, fixed owners for dynamically allocated objects. Prefer to transfer ownership with smart pointers.

Boost

link
Use libraries from the Boost library collection.

C++11

link
Use libraries and language extensions from C++11 when appropriate.

Comments

Though a pain to write, comments are absolutely vital to keeping our code readable. While comments are very important, the best code is self-documenting. Giving sensible names to types and variables is much better than using obscure names that you must then explain through comments.

Comment Style

link
Use the // syntax for comments.

File Comments

link
Start each file with the description of its contents.

Class Comments

link
Every class definition should have an accompanying comment that describes what it is for and how it should be used.

Function Comments

link
Declaration comments describe use of the function; comments at the definition of a function describe operation.

Variable Comments

link
In general the actual name of the variable should be descriptive enough to give a good idea of what the variable is used for. In certain cases, more comments are required.

Implementation Comments

link
In your implementation you should have comments in tricky, non-obvious, interesting, or important parts of your code.

Punctuation, Spelling and Grammar

link
Pay attention to punctuation, spelling, and grammar; it is easier to read well-written comments than badly written ones.

TODO Comments

link
Use TODO comments for code that is temporary, a short-term solution, or good-enough but not perfect.

Deprecation Comments

link
Mark deprecated interface points with DEPRECATED comments.

Formatting

Coding style and formatting are pretty arbitrary, but a project is much easier to follow if everyone uses the same style. Individuals may not agree with every aspect of the formatting rules, and some of the rules may take some getting used to, but it is important that all project contributors follow the style rules so that they can all read and understand everyone's code easily.

To help you format code correctly, there are some tools available. See Formatting Tools for more information.

Line Length

link
Each line of text in your code should be at most 80 characters long.

Non-ASCII Characters

link
Non-ASCII characters should be rare, and must use UTF-8 formatting.

Spaces vs. Tabs

link
Use only spaces, and indent 4 spaces at a time.

Function Declarations and Definitions

link
Return type on the same line as function name, parameters on the same line if they fit.

Function Calls

link
On one line if it fits; otherwise, wrap arguments at the parenthesis.

Braced Initializer Lists

link
Format a braced list exactly like you would format a function call in its place.

Conditionals

link
Prefer no spaces inside parentheses. The else keyword belongs on a new line.

Loops and Switch Statements

link
Switch statements may use braces for blocks. Annotate non-trivial fall-through between cases. Empty loop bodies should use {} or continue .

Pointer and Reference Expressions

link
No spaces around period or arrow. Pointer operators do not have trailing spaces.

Boolean Expressions

link
When you have a boolean expression that is longer than the standard line length , be consistent in how you break up the lines.

Return Values

link
Do not needlessly surround the return expression with parentheses.

Variable and Array Initialization

link
Your choice of = , () , or {} .

Preprocessor Directives

link
The hash mark that starts a preprocessor directive should always be at the beginning of the line.

Class Format

link
Sections in public , protected and private order, each indented one space.

Constructor Initializer Lists

link
Constructor initializer lists can be all on one line or with subsequent lines indented four spaces.

Namespace Formatting

link
The contents of namespaces are not indented.

Horizontal Whitespace

link
Use of horizontal whitespace depends on location. Never put trailing whitespace at the end of a line.

Vertical Whitespace

link
Minimize use of vertical whitespace.

Formatting Tools

There are various tricks and utilities that we use to make C++ code more robust, and various ways we use C++ that may differ from what you see elsewhere.

astyle

link
Use Artistic Style to auto-format your code.

.emacs

link
Use the lisp commands listed in cued.emacs to initialise emacs to confirm to this style guide.

auto-complete tool in emacs

link
Use auto-complete-tool for emacs and include the commands in cued.emacs file to your ~/.emacs file.

Parting Words

Use common sense and BE CONSISTENT .

If you are editing code, take a few minutes to look at the code around you and determine its style. If they use spaces around their if clauses, you should, too. If their comments have little boxes of stars around them, make your comments have little boxes of stars around them too.

The point of having style guidelines is to have a common vocabulary of coding so people can concentrate on what you are saying, rather than on how you are saying it. We present global style rules here so people know the vocabulary. But local style is also important. If code you add to a file looks drastically different from the existing code around it, the discontinuity throws readers out of their rhythm when they go to read it. Try to avoid this.

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


Based on
Bjarne Stroustrup's C++ Style and Technique FAQ
C++ Coding Standards
C++ Style Tips
Google's Style Sheet Revision 3.274
C++ Programming Style Guidelines