14.code Convention I
14.code Convention I
Programming
13. Code Conventions
Part I
Federico Busato
2024-11-05
Table of Contents
1/76
Table of Contents
4 Preprocessing
Macro
Preprocessing Statements
2/76
Table of Contents
5 Variables
static Global Variables
Conversions
6 Enumerators
7 Arithmetic Types
Signed vs. Unsigned Integral Types
Integral Types Conversion
Integral Types: Size and Other Issues
Floating-Point Types
3/76
Table of Contents
8 Functions
Functions Parameters
Functions Arguments
Function Return Values
Function Specifiers
Lambda Expressions
4/76
Table of Contents
5/76
C++ Project
Organization
“Common” Project Organization
6/76
Project Directories 1/2
Fundamental directories
include Project public header files
src Project source/implementation files and private headers
test (or tests) Source files for testing the project
Empty directories
bin Output executables
build All intermediate files
doc (or docs) Project documentation
7/76
Project Directories 2/2
Optional directories
submodules Project submodules
utils (or tools, or script) Scripts and utilities related to the project
README.md
• README template:
- Embedded Artistry README Template
- Your Project is Great, So Let’s Make Your README Great Too
LICENSE
10/76
File extensions
11/76
“Common” Project Organization Notes
• The main file (if present) should be placed in src/ and called main.cpp
12/76
“Common” Project Organization Example
<project name>
include/ README.md
public header.hpp CMakeLists.txt
src/ Doxyfile
private header.hpp LICENSE
templ class.hpp build/ (empty)
templ class.i.hpp bin/ (empty)
(template/inline functions) doc/ (empty)
templ class.cpp test/
(specialization) my test.hpp
subdir/ my test.cpp
my file.cpp ...
13/76
“Common” Project Organization - Improvements
14/76
Alternative - “Canonical” Project Organization 1/2
• Header and source files (or module interface and implementation files) are next
to each other (no include/ and src/ split)
• Headers are included with <> and contain the project directory prefix, for
example, <hello/hello.hpp> (no need of "" syntax)
• Header and source file extensions are .hpp / .cpp ( .mpp for module
interfaces). No special characters other than and - in file names with . only
used for extensions
• A source file that implements a module’s unit tests should be placed next to that
module’s files and be called with the module’s name plus the .test second-level
extension
17/76
Coding Styles and
Conventions
Overview
18/76
Overview
19/76
Overview
20/76
Code Quality
21/76
Bad Code
22/76
abstrusegoose.com/432
Coding Styles Overview
This section, including the review of all coding styles, has been updated on October 2024
23/76
Popular Coding Styles 1/3
25/76
Popular Coding Styles 3/3
Secure Coding
26/76
Static Analysis Tools
• clang-tidy
clang.llvm.org/extra/clang-tidy/checks/list.html
• PVS-Studio
pvs-studio.com/en/docs/warnings
• SonarSource
rules.sonarsource.com/cpp/
• cpp-checks
sourceforge.net/p/cppcheck/wiki/ListOfChecks/
Note: each tool also provides the list of checks that are evaluated 27/76
Legend
※ → Important!
Highlight potential code issues such as bugs, inefficiency, or important
readability problems. Should not be ignored
∗ → Useful
It is not fundamental, but it emphasizes good practices and can help to prevent
bugs. Should be followed if possible
• → Minor / Obvious
Style choice, not very common issue, or hard to enforce
28/76
Header Files and
#include
Header Files 1/2
30/76
#include Guard
※ Ensure a unique name for the include guard, e.g. project name + path
.Googleq
..........
31/76
#include Syntax
"" syntax
∗ Should be absolute paths from the project include root .Google,
. . . . . . . . . Mozilla,
. . . . . . . . . . . .Hic
....
e.g. #include "directory1/header.hpp"
<> syntax
32/76
Order of #include
. . . . . . . . Webkit,
LLVM, .......... .... . . . . . . . CoreCpp
Mozilla, ............
(1) Main module/interface header, if exists (it is only one)
• space
(2) Current project includes
• space
(3) Third party includes
• space
(4) System includes
Motivation: System/third party includes are self-contained, local includes might not
• Report at least one function used for each include. It helps to identify unused
headers
<iostream> // std::cout, std::cin
34/76
Common Header/Source Filename Conventions
35/76
Example
// [ LICENSE ]
# ifndef PROJECT_A_MY_HEADER
# define PROJECT_A_MY_HEADER
// ..
# endif // PROJECT_A_MY_HEADER
36/76
Preprocessing
Macro 1/3
※ Macros should be unique names, e.g. use a prefix for all macros related to a
project MYPROJECT MACRO . . . . . . . . . . Unreal,
Google, . . . . . . . . . . CoreCpp
............
38/76
Macro 3/3
∗ Close #endif with a comment with the respective condition of the first #if
# if defined(MACRO)
...
# endif // defined(MACRO)
∗ The hash mark that starts a preprocessor directive should always be at the
beginning of the line ..........
Google
# if defined(MACRO)
# define MACRO2
# endif
40/76
Preprocessing Statements 2/2
41/76
Variables
Variables 1/2
※ Place variables in the narrowest scope possible. Declare variables close to the
first use . . . . . . . . . . . .1 , .CoreCpp
. . . . . . . . . . CoreCpp
Google, . . . . . . . . . . . 2 , CoreCpp
. . . . . . . . . . . .3
• It is allowed to declare multiple variables in the same line for improving the
readability, expect for pointer or reference ..........
Google
(only one declaration per line) CoreCpp
............
42/76
Variables 2/2
∗ Avoid static global variables unless they are trivially destructible Google
..........
e.g. std::string str = is not trivially destructible
- static local variables with dynamic initialization are allowed
∗ Avoid static global variables unless they are trivially constructible and
destructible ........
LLVM
∗ Use const cast to remove the const qualifier only for pointers and references
..........
Google
• Avoid const cast to remove const , except when implementing non- const
getters in terms of const getters .............
Chromium
∗ Use std::bit cast to interpret the raw bits of a value using a different type of
the same size . . . . . . . . . .45/76
Google
Enumerators
Enumerators
• Specify the underlying type and enumerator values only when necessary
. . . . . . . . . . . 1 , CoreCpp
.CoreCpp . . . . . . . . . . . .2
enum class MyEnum : int16_t { Abc = 1, Def = 2 }; // bad
• Do not apply unary minus to operands of unsigned type, e.g. -1u . . . .47/76
.Hic
Integral Types Conversion
48/76
Integral Types: Size and Other Issues
Size:
※ Except int , use fixed-width integer type (e.g. int64 t , int8 t , etc.)
.Chromium,
. . . . . . . . . . . . Unreal,
. . . . . . . . . . Google, . . . . .µOS,
. . . . . . . . . . .Hic, . . . . . .Clang-Tidy
...............
Other issues:
49/76
Floating-Point Types 1/2
50/76
Floating-Point Types 2/2
• Floating-point literals should always have a radix point, with digits on both sides,
even if they use exponential notation 2.0f . . . . . . . . . . (opposite)
. . . . . . . . . . Webkit
Google,
51/76
Functions
Functions 1/2
∗ Prefer pure functions, namely functions that always returns the same result
given the same input arguments (no external dependencies) and does not modify
any state or have side effects outside of returning a value ............
CoreCpp
52/76
Functions 2/2
53/76
Functions Parameters 1/4
54/76
Functions Parameters - Input/Output 2/4
※ Pass-by- const -pointer or reference for input parameters are not intended to
be modified by the function .Google,
. . . . . . . . . . .Unreal
.........
55/76
Functions Parameters - By-Value, By-Rvalue 3/4
∗ Don’t use rvalue references && except for move constructors and move
assignment operators ..........
Google
56/76
Functions Parameters 4/4
• All parameters should be aligned if they do not fit in a single line (especially in the
declaration)
void f(int a,
const int* b);
57/76
Functions Arguments
• All arguments should be aligned to the first one if they do not fit in a single line
..........
Google
my_function(my var1, my_var2,
my_var3); 58/76
Function Return Values 1/2
• Use trailing return types only where using the ordinary syntax is impractical or
much less readable .Google,
. . . . . . . . . Webkit
..........
int foo(int x) instead of auto foo(int x) -> int 59/76
Function Return Values 2/2
※ Transfer ownership with smart pointers. Never return pointers for new objects.
Use std::unique ptr instead .Google,
. . . . . . . . . . .Chromium,
. . . . . . . . . . . . . CoreCpp
............
int* f() { return new int[10]; } // wrong!!
std::unique_ptr<int> f() { return new int[10]; } // correct
60/76
Function Specifiers
• Do not separate declaration and definition for template and inline functions
..........
Google
• Use inline only for small functions (e.g. ≤ 10 lines, no loops or switch
statements) .Google,
. . . . . . . . . Hic,
. . . . . CoreCpp
............
61/76
• Use noexcept when it is useful and correct ..........
Google
Lambda Expressions
∗ Prefer explicit captures if the lambda may escape the current scope ..........
Google
• Use default capture by reference ( [&] ) only when the lifetime of the lambda is
obviously shorter than any potential captures .Google,
. . . . . . . . . . CoreCpp
............
∗ Use struct only for passive objects that carry data; everything else is
class .Google,
. . . . . . . . . . CoreCpp
............
∗ Use class rather than struct if any member is non- public ............
CoreCpp
63/76
Initialization
※ Objects are fully initialized by constructor calls and all resources acquired
must be released by the class’s destructor
. . . . . . . . . . CoreCpp
Google, . . . . . . . . . . . .2 , .Hic,
. . . . . . . . .. . .1 CoreCpp . . . . .Clang-Tidy
...............
• Do not use braced initializer lists {} for constructors (at least for containers, e.g.
std::vector ). It can be confused with std::initializer list ........
LLVM
65/76
Special Member Functions
66/76
=default, =delete
67/76
Structs and Classes - Other Issues 1/2
• Don’t define a class or enum and declare a variable of its type in the same
statement, e.g. struct Data /*...*/ data; ............
CoreCpp
68/76
Structs and Classes - Other Issues 2/2
∗ Place free-functions that interact with a class in the same namespace, e.g.
operator== ............
CoreCpp
∗ Declare data members private , unless they are constants. This simplifies
reasoning about invariants . . . . . . . . . . .Hic
Google, ....
69/76
Inheritance 1/2
Examples:
- Trailing underscore (e.g. member var ) . . . . . . . . . . .µOS,
Google, . . . . . Chromium
.............
- Leading underscore (e.g. member var ) .NET
- Public members (e.g. m member var , mVar ) .Webkit,
......... ...........
Mozilla
- Static members (e.g. s static var , sVar ) ..........
Webkit, ...........
Mozilla
Personal Comment: Prefer member var as I read left-to-right and is less invasive
class B {
public:
B();
void public_function();
protected:
int _a; // in general, it is not public in derived classes
void _protected_function(); // "protected_function()" is not wrong
// it may be public in derived classes
private:
int _x;
float _y;
75/76
Structs and Classes - Style 5/5
• Do not use get for observer methods ( const ) without parameters, e.g.
get size() → size() ..........
Webkit
• Precede getters that return values via out-arguments with the word get
.............
Chromium
• Precede setters with the word set . Use bare words for getters 76/76
Webkit, Chromium