Skip to the content.

%C++ Coding Rules
Lovely rules for happy developers
Version: xxxxxxx
%olibre@Lmap.org %date

Main goal

Audience

This document is written by developers for developers.
Here β€œWe” means β€œWe the delevopers” (Nous, les dΓ©veloppeurs).

Rationale

We all hate coding rules, often written by poor programmers with weak experience with C++.
Coding rules become outdated, may not be understood by their users, and do not always provide guidance.

But a minimum of rules are required for source code consistency accross our projects.

Therefore, this document aims to provide lovely rules for happy devs:

Exceptions

Continuous improvement

We prefer an helpful guide rather than a list of static outdated restrictions. Please help maintening this document: suggest/add/remove/clarify/simplify rules.

Choose the way you want to contribute:

Notation shortcuts

Files

F.SRC Β  C++ filename is ClassName.[hc]pp

class MyNewClass -> MyNewClass.hpp // C++ header
                    MyNewClass.cpp // C++ implementation
// Good
MsgProcessorV4.cpp
ISession.hpp
ISession.cpp
MyNewClass.cpp

// Bad
MsgProcessorV4.cc    // C++ source must be '*.cpp'
ISession.h           // C++ header must be '*.hpp'
isession.cpp         // Must be same as the class name
My_New_Class.cpp     // Must be same as the class name

F.RST Β  Rest in lower_case

// Good
foo/bar_configuration.xml

// Bad
Foo/barconfiguration.xml

F.INC Β  Include headers

Most of recent libraries use the following convention:

projectname
β”œβ”€β”€ include
β”‚   └── projectname
β”‚       └── PublicHeader.hpp
└── src
    β”œβ”€β”€ CompilationUnit.cpp
    └── PrivateHeader.hpp

To include public headers of the library projectname:

#include <projectname/PublicHeader.hpp>

Compilation flag:

gcc app.cpp -I projectname/include

Bad source code organization because does permit #include <projectname/example.hpp>:

projectname
β”œβ”€β”€ include
β”‚   └── PublicHeader.hpp    ## BAD: sub-directory projectname is missing
└── src
    β”œβ”€β”€ CompilationUnit.cpp
    └── PrivateHeader.hpp

Accepted source code organization in order to simplify file tree depth:

projectname
β”œβ”€β”€ projectname             ## GOOD: sub-directory projectname is present
β”‚   └── PublicHeader.hpp
└── src
    β”œβ”€β”€ CompilationUnit.cpp
    └── PrivateHeader.hpp

gcc app.cpp -I projectname

Bad source code organization because headers and source files are separated too much:

β”œβ”€β”€ cmake
β”œβ”€β”€ doc
β”œβ”€β”€ include              Public headers
β”‚   β”œβ”€β”€ config
β”‚   β”œβ”€β”€ log
β”‚   β”œβ”€β”€ monitor
β”‚   β”œβ”€β”€ persistence
β”‚   └── utilities
β”œβ”€β”€ src                  Private headers and compilation units
β”‚   β”œβ”€β”€ config
β”‚   β”œβ”€β”€ log
β”‚   β”œβ”€β”€ monitor
β”‚   β”œβ”€β”€ persistence
β”‚   └── utilities
└── test
    β”œβ”€β”€ config
    β”œβ”€β”€ log
    β”œβ”€β”€ monitor
    β”œβ”€β”€ persistence
    └── utilities

Accepted source code organization to keep together corresponing *.hpp and *.cpp:

β”œβ”€β”€ cmake
β”œβ”€β”€ doc
└── src
    β”œβ”€β”€ config           Public headers and compilation units
    β”‚   β”œβ”€β”€ private      Private headers
    β”‚   └── test
    β”œβ”€β”€ log
    β”‚   β”œβ”€β”€ private
    β”‚   └── test
    β”œβ”€β”€ monitor
    β”‚   └── test
    β”œβ”€β”€ persistence
    β”‚   └── test
    └── utilities
        β”œβ”€β”€ private
        └── test

F.ICM Β  Spread include directories

CMake can help managing dependencies and public headers location because CMake spreads compilation directives from dependees to dependers.

Therefore teams can decide and change the file tree organisation indivually for their sub-module without impacting the dependent teams.

Following *.cmake example defines the include directory (other target properties are also defined)

file (GLOB hpp_files ${CMAKE_CURRENT_LIST_DIR}/*.hpp)
file (GLOB cpp_files ${CMAKE_CURRENT_LIST_DIR}/*.cpp)
source_group ("SubProjectName Headers" FILES ${hpp_files})
add_library (SubProjectName ${cpp_files} ${hpp_files})
target_include_directories (SubProjectName PUBLIC ${CMAKE_CURRENT_LIST_DIR}/..)        # Location of public headers
target_link_libraries (SubProjectName PUBLIC config monitor log)
include (${CMAKE_CURRENT_LIST_DIR}/test/test.cmake)

Following *.cmake example disables dependee header warnings (compiler does not print dependee header warning when compiling depender)

add_library (gtest ${CMAKE_CURRENT_LIST_DIR}/googletest/src/gtest-all.cc)
# keyword SYSTEM disables compilation warning (e.g. keyword SYSTEM replaces -I by -isystem)
target_include_directories (gtest SYSTEM PUBLIC  ${CMAKE_CURRENT_LIST_DIR}/googletest/include)
target_include_directories (gtest        PRIVATE ${CMAKE_CURRENT_LIST_DIR}/googletest)
find_package (Threads)
target_link_libraries (gtest Threads::Threads)
if (CMAKE_COMPILER_IS_GNUC OR CMAKE_C_COMPILER_ID STREQUAL "Clang")
    target_compile_options (gtest PRIVATE -w)         # Flag -w disables compilation warning
endif()

F.IQC Β  Double quotes "" and angle brackets <>

Local header (in same directory)

This example uses:

Examples

#include "MyHeader.hpp"              // "" when in the same directory as the current C++ file
#include "private/PrivateHeader.hpp" // "" in a sub-directories of the current C++ file
#include "xxxx/PublicHeader.hpp"     // "" public header of same module (if in a different directory)

#include "other_module/Header.hpp"   // You can choose "" or <> to include
#include <other_module/Header.hpp>   // from another module of same project

#include <3rdparty/xxx/External.hpp> // <> for third parties
#include <iostream>                  // <> for system headers

Include external after or before local headers

The sequence of #include is not important as long as the project compiles using any order. A simple check is to include first the headers of the current sub-module, then libraries, third-parties and finally the system headers (as in the above example).

Moreover the unit test compilation unit first includes the header to be tested:

/// File MyClass_spec.cpp in order to test the class MyClass

#include "myproject/MyClass.hpp"   // This checks that MyClass.hpp includes all its dependencies
#include "MyClass_spec.hpp"
#include <gtest/gtest.h>
#include <string>

Include local header directly

The following bash script replaces #include <dir/header.h> by #include "header.h" when both files (header and includer) are in the same directory:

find -name "*.h*" -printf '%f\n' |
while read h
do
    fgrep "/$h" -RI | fgrep -w 'include' | tr -d '\r' |
    awk -F'[:# ]*include *[<"]' '{print $1 "\t" $2}' |
    while read f g
    do
        [[ -f "${f%/*}/$h" ]] &&
        sed "s|.$g|\"$h\"|" -i "$f"
    done
done

The above script may mix header having same filename. Therefore this is another script to control the result of the previous script when headers have same filename:

find -type f -printf '%f\n' |
sort | uniq -d |
while read f
do
    echo ________________________________
    find -name "$f"
    git diff | tac | sed -n "/$f/,/^---/p" | tac
done

Or this alternative if you like diff-hilighting of your editor:

find -type f -printf '%f\n' |
sort | uniq -d |
while read f
do
    git diff | tac | sed -n "/$f/,/^---/p" | tac | tee out
    [[ -s out ]] && echo --------------- &&
                 find -name "$f" &&
                 echo _________________________________
done | tr -d '\r' | vim -

(tiny command line tac | sed -n "/$f/,/^---/p" | tac is from Sundeep at question Print the smallest set of lines between two patterns)

F.GRD Β  Header-guard #define FILE_HPP_

Example for file: foo/bar/ISessionV4.hpp

#ifndef FOO_BAR_ISESSION_V4_HPP_
#define FOO_BAR_ISESSION_V4_HPP_
// ...
// ...
// ...
#endif  // end of header-guard
/** 
* \copyright Copyright (C) 2015-2016 MyCompany
*            All Rights Reserved
*            DO NOT ALTER OR REMOVE THIS COPYRIGHT NOTICE
* 
* \file
* \brief <description of file purpose>
* ...
*/

F.DXG Β  Doxygen compliance

  1. Doxygen comment at the top of every C++ file (brief description and copyright).
  2. Doxygen comment for class and function in the header file (see doxygen.org).
  3. No duplication of Doxygen comments in the *.cpp file (i.e. the good place is the header file)
/**
 * Header file for class MyMessage
 *
 * \brief The header for the MyMessage class
 *
 */

F.TDO Β  Use FIXME TODO TOREVIEW

Label Jenkins priority Meaning
FIXME High When the hack or hardcoded constant [or …] is critical and should be removed before the next release. Usually FIXME is used to do a fast prototyping.
TODO Normal Explain some improvments or when you have to do a (usually complex) change, or you are too lazy to do it in that particular moment. If it is something critical, and the software could not be released without that code or fix, then use a FIXME. On the other hand, if the change will not affect the proper behaviour of the program, and you are comfortable in leaving the code as it is, then use TODO.
TOREVIEW Low β€œplease review this code with special attention”, regardless of the usual review process.

Rationale:

// Formatting
blabla; // TODO (YourName@example.com): What needs to be done
blabla; // TODO: Deadline DATE

// Good
blabla; // TODO (JohnDoe@example.com): Update function to provide concatenation operator
blabla; // TODO: Deadline November 2012.
/**
 * TODO (JohnDoe@example.com): Remove 32-bits ID once all clients have migrated to 64-bit ID
 */

// Bad
blabla; // TODO
blabla; // todo: refactor blabla

F.IDT Β  Indentation is 4 spaces

F.ALM Β  Allman style

Full Allman style using 4 spaces indentation

#include <iostream>

int main (int argc, char *argv[])
{
    if (argc > 1)
    {
        std::cout << argv[1] << std::e ndl;
    }

    for (int i = 0; i < 9; ++i)
    {
        if (i == 5)
            continue;

        if (i % 2)
        {
            std::cout << i << std::endl;
        }

        if (i > 5)
        {
            std::cout << 9 - i << std::endl;
        }
        else
        {
            std::cout << 2 + i << std::endl;
        }
    }

    return 0;
}

Same code but using style 1TBS for short blocks

#include <iostream>

int main (int argc, char *argv[])
{
    // Good: Allman style at large scope
    if (argc > 1)
    {
        std::cout << argv[1] << std::endl;
    }

    // Good: Allman style for long block
    for (int i = 0; i < 9; ++i)
    {
        if (i == 5)  continue;  // One line accepted (but not nice to debug)

        // 1TBS accepted for tiny block
        if (i % 2) {
            std::cout << i << std::endl;
        }

        // 1TBS also accepted here but block should stay tiny
        if (i > 5) {
            std::cout << 9 - i << std::endl;
        } else {
            std::cout << 2 + i << std::endl;
        }
    }

    return 0;
}

F.80C Β  Keep line length acceptable

The 80 column rule is still common in coding standards today (for example: Google’s Java and Linux kernel standards).

Do not worry, there is no such limit in our coding rules.

However keeping lines short is nice:

Image of a merge using a 3-way diff

F.WSP Β  No trailing whitespaces

When some devs leave trailing spaces and others remove them, the repository becomes to be polluted by these unrelevant changes. In order to avoid this noise, we can remove trailing whitespaces before/during commit.

F.EOL Β  Line Feed "\n" (LF)

When some devs work on MS-Windows and others on Unix platforms, ASCII files may contain both End Of Line:

Rules for every ASCII file:

F.EOF Β  Clean end of file

When a file is cut (end of file is missing), a simple trick is to check

In order to detect a potential file corruption (i.e. when the end of the file is missing), we usually check the last character of the file. File can be considered as OK when its last character is a newline.

Moreover final blank lines are not necessary and some devs may clean them produising some noise within the commit diff.

Rules:

See also Clang compiler option -Wnewline-eof.

Naming

No Hungarian notation as modern IDEs display underlying types.

Main idea

Notation Meaning
UPPER_CASE Macros and Constants
PascalCase and lower_case_type Types and nested types
camelCase and lower_case Functions and Variables

N.MCR Β  Macro in UPPER_CASE

// Good
#define FIND_ROOT(x)
#define PI_ROUNDED 3.14
#ifdef BIG_ENDIAN

// Bad
#define FINDROOT(x)
#define piRounded 3.14
#ifdef BigEndian

N.CST Β  Constant/Enum in UPPER_CASE

Priority:

// Bad
#define       max_counter   20    // Name must be UPPER_CASE
const int32_t iMaxCounter = 20;

// Correct
#define MAX_COUNTER 20

// Good
enum {               MAX_COUNTER = 20 };
const        int32_t MAX_COUNTER = 20;
static const int32_t MAX_COUNTER = 20;

// Better
constexpr int32_t MAX_COUNTER = 20;

// unnammed-namespace is better than above 'static const'
namespace
{
const        int32_t MAX_COUNTER = 20; // Link is external in C++03 and internal since C++11
static const int32_t MAX_COUNTER = 20; // Link is internal for both
}

See also codeproject.com/The One Definition Rule in C++11 and C++14: Constant Expressions and Inline Functions.

N.TYP Β  Types in PascalCase

// Good
struct Session;
class  FooSession;

class MyNewClass
{
  // .. lots of lines

}; // end of MyNewClass

// Bad
struct session;
class foo_session;
class myNewClass;

N.ITF Β  Interface in IPascalCase

// Good
IReactor;
ISession;
IFooSession;
IMsgProcessor;

// Bad
Ireactor;
isession;
I_Foo_Session;
imsgprocessor;

N.FCN Β  Function in camelCase

// Good
class Acceptor
{
public:
    int32_t initialize();
    int32_t getValue();
    int32_t findValue();
    int32_t setValue();
};

// Bad
class Acceptor
{
public:
    int32_t initializeAcceptor();  // Redundancy name of the class
    int32_t GetValue();            // First word is not full lowercase
    int32_t find_value();          // Can be accepted if consistent with the whole
    int32_t setvalue();            // Missing Capital on second word
};

N.PRM Β  Function parameter in camelCase

/// Divides the quantity by two
int32_t divideByTwo (int32_t qty, bool /*force*/) { return qty/2; }

/// Divides the quantity by two
/// \param[in] force dummy comment
int32_t divideByTwo (int32_t qty, bool UNUSED(force)) { return qty/2; }

/// Divides the quantity by two
int32_t divideByTwo (int32_t         qty,    ///<[in] quantity
                     bool DEBUG_ONLY(force)) ///<[in] dummy comment
{
    assert(force==true || force==false);
    return qty/2;
}

N.TTP Β  Type template parameter PascalCase_t expresses the capability

template<typename Callable,  template<typename> typename BigContainer, typename ForwardArray = MyClassArray>
class MyClass
{
    Callable                   _callback;
    BigContainer<ForwardArray> _container;
};

N.NTP Β  Non-type template parameter UPPER_CASE (or PascalCase)

template<size_t SIZE = 512>
class MyClass
{
    int32_t _myArray[SIZE];
};

N.LCL Β  Local variable in camelCase

// Good
Session session1;
MyClass myClass;

// Bad
Session Session1; // Name must start with a lowercase letter
MyClass my_class; // Can be accepted if consistent

N.STR Β  Struct data member in camelCase

struct Limit
{
    int32_t quantity;    // Good
    double  price;       // Good
    double  limitPrice;  // Bad - Duplicated word 'limit' with struct name
    bool    isActive;
};

N.CLS Β  Class data member in _camelCase

Rationale:

class MyClass
{
public:
    double getTradingVolume() const;

private:
    int32_t _quantity;
    double  _price;
    bool    _isActive;
};

double MyClass::getTradingVolume() const
{
    return _price * _quantity;
}

See also related questions:

N.GBL Β  Global variables prefixed by //

ISO C++ recommandation:

The names of global variables should start with //.

Ideal way to use a global variable:

// my_global_variable;
^^ // The leading "//" improves this global variable

It’s a joke.

Sort of.

The truth is that there are cases when global variables are less evil than the alternatives β€” when globals are the lesser of the evils. But they’re still evil. So wash your hands after using them. Twice.

Instead of using a global variable, you should seriously consider if there are ways to limit the variable’s visibility and/or lifetime, and if multiple threads are involved, either limit the visibility to a single thread or do something else to protect the system against race cases.

Note: if you wish to limit the visibility but neither lifetime nor thread safety, two of the many approaches are to either move the variable into a class as a static data member or to use an unnamed namespace.

Here is how to move the variable into a class as a static data member:

class Foo
{
    // ...
    static int g_xyz// See the Construct Members On First Use Idiom
    // ...
};

Here is how to use an unnamed namespace:

namespace
{
int g_xyz;  // See the Construct On First Use Idiom for non-members
}

Repeat: there are three major considerations: visibility, lifetime, and thread safety. The above examples address only one of those three considerations.

N.NSP Β  Namespace in lower_case

// Good
namespace foo {
namespace bar
{

class Limit
{
public:
    // functions...

private:
    // data...

}; // End class Limit

}  // End namespace foo
}  // End namespace ct

// Bad
namespace FOO { namespace BAR
  {
    class Limit
    {
    public:
      // functions...

    private:
      // data...

    };
  }
}

// Better: C++17 (already available on recent compiler versions)
namespace foo::bar
{

class Limit
{
public:
    // functions...

private:
    // data...

}; // End class Limit

}  // End namespace foo::bar

N.BDP Β  Follow BaseDerived pattern

// In the following examples, "IMsg" is the Base name
class IMsg;

// Good order "Base -> Derived"
class IMsgProcessor;
class IMsgManager;
class IMsgLogon;

// Bad order "Base -> Derived"
class IProcessorMsg;
class IManagerMsg;
class ILogonMsg;

N.ABR Β  No ambiguous abbreviations

Google recommendations:

Give as descriptive a name as possible, within reason. Do not worry about saving horizontal space as it is far more important to make your code immediately understandable by a new reader. Do not use abbreviations that are ambiguous or unfamiliar to readers outside your project, and do not abbreviate by deleting letters within a word.

Our rules:

// Good
int price_count_reader; // No abbreviation
int num_errors;         // "num" is a widespread convention for 'numbers of'
int num_dns_connections;// Most people know what "DNS" stands for

// To be reviewed
int n;                  // May be long enough in small scopes (for-loop, tiny function...)
int nerr;               // Ambiguous abbreviation but same remark as for "int n;"

// Bad
int n_comp_conns;       // Ambiguous abbreviation
int wgc_connections;    // Only your group knows what this stands for
int pc_reader;          // Lots of things can be abbreviated "pc"
int cstmr_id;           // Deletes internal letters

N.EGL Β  All code in English

int price;   // Good
int precio;  // Bad
int prix;    // Bad
int preis;   // Bad

Coding

OK for safe code, but no performance sacrificed, we are C++ devs!

C.SZT Β  Explicit-sized integer types

C.INI Β  Always initialize variables

The following parenthesis initialization ambiguity is known as the Most vexing parse. Check the compilation on gcc.godbolt.org.

#include <stdint.h> 

// Parenthesis can also be Bad
float foo (float param)
{                               // Function declarartion
    float  ret( float(param) ); // float ret( float );
    return ret;
} 

// Use instead braces (C++11)
float bar (float param)
{
    float  ret{ float(param) }; // No ambiguity
    return ret;
} 

// C++11 uniform initialization syntax (initializers)
int32_t quantity {0};
float   price    {0.0};
char*   text     {nullptr};

Note: Value initialization changed since C++11. Value initialization is when parentheses/braces are empty: T(); T{}; new T(); new T{};

Build/Run below snippet on Coliru

#include <iostream>

struct A
{
    A() {} // ctor does not initialize 'i'
    int i;
};

struct B // implicit ctor
{
    A a;
    int i;
    void set() { a.i = i = 42; }
};

std::ostream& operator<< (std::ostream& os, const B& b)
{
    os <<'\t'<< b.a.i <<'\t'<< b.i;
    return os;
}

int main()
{
    std::cout <<"----------"<< __cplusplus <<"----------" "\n";

    B b; // used to reset memory for 'placement new'

    b.set(); std::cout <<"new(&b)B   "<< *new(&b)B   <<'\n'; // All uninitialized (in all C++ standards)

    std::cout          <<"       B() "<< B()         <<'\n'; // B::A::i uninitialized in C++03, zero-initialized in C++11
    b.set(); std::cout <<"new(&b)B() "<< *new(&b)B() <<'\n'; // B::i zero-initialized (in all C++ standards)

#if __cplusplus > 2011*100                                   // B{} is aggregate-initialization (DR1301)
    std::cout          <<"       B{} "<< B{}         <<'\n'; // => B::A::i value-initialized
    b.set(); std::cout <<"new(&b)B{} "<< *new(&b)B{} <<'\n'; // => B::i     zero-initialized
#endif
}

Build output & Possible run output

> clang++ --version
clang version 3.7.0 (tags/RELEASE_370/final 246979)
Target: x86_64-unknown-linux-gnu
Thread model: posix

> clang++ -std=c++03 -Wall -Wextra -pedantic main.cpp && ./a.out
----------199711----------
new(&b)B   	42	    42
       B() 	0	    0
new(&b)B() 	0	    0

> clang++ -std=c++11 -Wall -Wextra -pedantic main.cpp && ./a.out
----------201103----------
new(&b)B   	42	    42
       B() 	0	    0
new(&b)B() 	0	    0
       B{} 	4196348	0
new(&b)B{} 	42	    0

> clang++ -std=c++14 -Wall -Wextra -pedantic main.cpp && ./a.out
----------201402----------
new(&b)B   	42	    42
       B() 	0	    0
new(&b)B() 	0	    0
       B{} 	4196348	0
new(&b)B{} 	42	    0

> clang++ -std=c++1z -Wall -Wextra -pedantic main.cpp && ./a.out    
----------201406----------
new(&b)B   	42	    42
       B() 	0	    0
new(&b)B() 	0	    0
       B{} 	4196348	0
new(&b)B{} 	42	    0

C.INH Β  No public multi-inheritance

C.OVL Β  No operator overloading

C.CST Β  Use C++ style casts

int32_t j = static_cast<int32_t>(x);  // Good
int32_t j = (int32_t)x;               // Bad
int32_t j =  int32_t(x);              // Do not abuse!

C.CLS Β  Protect code from collision

#include <iostream>
#include <stdint.h>

namespace n1 {
namespace internal
{
int32_t x = 1;
}
using namespace internal;
int32_t y = 1;
int f1() { return x + y; }
} // namespace n1

namespace n2 {
namespace internal
{
double d = 2.0;
}
using namespace internal;
double y = 2.0;
/* Errors:
double f2() { return internal::x + y; } // 'x' is not a member of 'n2::internal'
double f3() { return           x + y; } // 'x' was not declared in this scope
*/
double f4() { return           d + y; }
} //namespace n2

int main()
{
    using namespace n1;
    using namespace n2;
    using namespace std;

    cout <<"f1()            "<< f1()            << endl;
    cout <<"f4()            "<< f4()            << endl;
    cout <<"n1::y           "<< n1::y           << endl;
    cout <<"n2::y           "<< n2::y           << endl;
    cout <<"n1::internal::x "<< n1::internal::x << endl;
    cout <<"n2::internal::d "<< n2::internal::d << endl;

    // Errors:
    // cout << internal::x << endl; // the same error as in f2
    // cout << y           << endl; // ambiguous n1 vs n2
}

C.HCV Β  No magic/hardcoded values

C.DTR Β  No exception in destructor

When an exception is thrown the program unwinds the stack (properly destruct the local variables). If during this unwinding process, a destructor throws a second exception then the behaviour is undefined as the language runtime can only propagate one single exception.

C.EXC Exception inherit std::exception

User-defined exceptions:

This make catching exception easier.

C.OVR Β  Non top-level virtual member functions use override

The override keyword expresses polymorphism intent and helps catch errors due to refactoring and design changes early.

C.UNS Use unnamed namespaces for compilation unit declarations

When you declare a symbol, either a function, a class or an instance, in a compilation unit, make sure you have good reason not to publish it in a header, then put it inside an unnamed (aka anonymous) namespace to prevent any conflict at link time.

C.WRN Β  Activate compilation warnings

Compiler flag Comment
-Wall Classic warnings
-Wextra Extra amount of warnings
-Weffc++ Effective C++ series of books from Scott Meyers
-pedantic Reject code not following ISO C++ (e.g. GNU extensions)
-pedantic-errors Pedantic warnings are converted into errors
-Winit-self Variables initialized with themselves (enabled by -Wall)
-Wswitch-enum Missing case for values of switch(enum)
-Wcast-align Incompatible alignment pointers
-Wcast-qual Cast between pointers leads to target type qualifier removal
-Wconversion Conversion might lead to value alteration, confusing overload resolution
-Wformat=2 Invalid argument types and format strings in formatting functions (printf, scanf…)
-Wuninitialized Variable used without being initialized
-Wmissing-field-initializers Fields is left uninitialized during (non-designated) structure initialization
-Wmissing-include-dirs User-supplied include directory does not exist
-Wpointer-arith [void and function] Operations addition/subtraction/sizeof are GNU extension
-Wredundant-decls Multiple declarations of the same entity is encountered in the same scope
-Wshadow Variable/typedef/struct/class/enum shadows another one having same name
-Wswitch Missing enumerated type in β€˜case’ labels
-fstack-protector-strong Checks for buffer overflows such as stack smashing attacks (extra code is added)
-Wstack-protector Warn if option β€˜-fstack-protector-strong’ complained about codes vulnerable to stack smashing
-Wunreachable-code Unreachable code
-Wunused Unused entity (functions, labels, variables, typedefs, parameters, …)
-Wwrite-strings Deprecated conversion from string literals to β€˜char *’ (enable by default in C++)
-fmax-errors=50 Limit number of errors to 50. Default is 0 => no limit.
-Werror=implicit-function-declaration Implicit function declarations allows to call functions without declaring them, and therefore is bug-prone because these functions use a different calling convention and have a fixed return type of int. Resulting issues are pointer truncation (on 64-bit architectures), exposure of padding bits (particular for bool-returning functions on x86_64), and unexpected lack of hardening. Implicit function declarations are not part of C++.
-Werror=implicit-int Implicit ints are usually source code bugs, and the presence of such code may interfere with future C language directions

Some develper use -Werror to fail compilation for any warning. But when -Werror is set within a build chain, a new compiler version or a change on third-party may fail the build for any minor warning. Please think also about people building your software.

Clang has a crazy compilation option -Weverything that enables all possible warnings. The idea is to enable all and disable the annoying ones.

Compiler flag Comment
-Weverything Β 
-Wno-c++98-compat Β 
-Wno-c++98-compat-pedantic Β 
-Wno-unused-macros Β 
-Wno-newline-eof Β 
-Wno-exit-time-destructors Β 
-Wno-global-constructors Β 
-Wno-gnu-zero-variadic-macro-arguments Β 
-Wno-documentation Β 
-Wno-shadow Β 
-Wno-missing-prototypes Β 
-fsave-optimization-record Indicate why some code has not been optimized (see C++FRUG #17)

See more on GCC warning options.

Extra coding guidelines

Style settings

The two following lines lines can be inserted to all C++ files:

// -*- mode: C++; coding: utf-8; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4; c-file-style: "linux" -*-
// vi:ft=cpp fenc=utf-8 ts=8 et sw=4 sts=4 tw=80

The first line is for Emacs and the second one for Vim.

See more details about these abreviated Vim settings:

Clang-format

For clang-format v3.8, create file .clang-format with the following content

    Language:        Cpp
    AccessModifierOffset: -4
    AlignAfterOpenBracket: Align
    AlignConsecutiveAssignments: true
    AlignConsecutiveDeclarations: true
    AlignEscapedNewlinesLeft: true
    AlignOperands:   true
    AlignTrailingComments: true
    AllowAllParametersOfDeclarationOnNextLine: true
    AllowShortBlocksOnASingleLine: true
    AllowShortCaseLabelsOnASingleLine: true
    AllowShortFunctionsOnASingleLine: Inline
    AllowShortIfStatementsOnASingleLine: true
    AllowShortLoopsOnASingleLine: true
    AlwaysBreakAfterReturnType: None
    AlwaysBreakBeforeMultilineStrings: true
    AlwaysBreakTemplateDeclarations: false
    BinPackArguments: true
    BinPackParameters: false
    BreakBeforeBraces: Custom    # Use BraceWrapping settings
    BraceWrapping:
      AfterClass:      true
      AfterControlStatement: false
      AfterEnum:       true
      AfterFunction:   true
      AfterNamespace:  false
      AfterStruct:     true
      AfterUnion:      true
      BeforeCatch:     true
      BeforeElse:      false
      IndentBraces:    false
    BreakBeforeBinaryOperators: false
    BreakBeforeTernaryOperators: false
    BreakConstructorInitializersBeforeComma: true     # Does not work :(
    ColumnLimit: 0
    CommentPragmas:  '^ IWYU pragma:'
    ConstructorInitializerAllOnOneLineOrOnePerLine: true
    ConstructorInitializerIndentWidth: 4
    ContinuationIndentWidth: 4
    Cpp11BracedListStyle: true
    DerivePointerAlignment: true
    DisableFormat:   false
    ExperimentalAutoDetectBinPacking: true
    ForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]
    IncludeCategories:
      - Regex:           '^".*\.hpp"'
        Priority:        1
      - Regex:           '^".*\.h"'
        Priority:        2
      - Regex:           '^<.*\.hpp>'
        Priority:        3
      - Regex:           '^<.*\.h>'
        Priority:        4
      - Regex:           '^<.*'
        Priority:        5
      - Regex:           '.*'
        Priority:        6
    # clang-format-3.8    IncludeIsMainRegex: (_spec)?$
    IndentCaseLabels: false
    IndentWidth:     4
    IndentWrappedFunctionNames: false
    KeepEmptyLinesAtTheStartOfBlocks: false
    MacroBlockBegin: ''
    MacroBlockEnd:   ''
    MaxEmptyLinesToKeep: 1
    NamespaceIndentation: None
    PenaltyBreakBeforeFirstCallParameter: 1
    PenaltyBreakComment: 300                     # JB put 60
    PenaltyBreakFirstLessLess: 120
    PenaltyBreakString: 1000
    PenaltyExcessCharacter: 1000000
    PenaltyReturnTypeOnItsOwnLine: 200
    PointerAlignment: Middle
    ReflowComments:  true
    SortIncludes:    true
    SpaceAfterCStyleCast: false
    SpaceBeforeAssignmentOperators: true
    SpaceBeforeParens: ControlStatements
    SpaceInEmptyParentheses: false
    SpacesBeforeTrailingComments: 2
    SpacesInAngles:  false
    SpacesInContainerLiterals: true
    SpacesInCStyleCastParentheses: false
    SpacesInParentheses: false
    SpacesInSquareBrackets: false
    Standard:        Auto            # JB put Cpp11
    TabWidth:        8               # JB put 4
    UseTab:          Never

In QtCreator, go in Tools > Options… > Beautifier > Clang Format, add above YAML as new customized style.