P.1 Express ideas directly in code
P.4 Ideally, a program should be statically type safe
P.5 Prefer compile-time checking to run-time checking
P.6 What cannot be checked at compile-time should be checkable at run-time
P.7 Catch run-time errors early
P.10 Prefer immutable data to mutable data
P.11 Encapsulate messy constructs, rather than spreading through the code
P.12 Use supporting tools as appropriate
P.13 Use support libraries as appropriate
I.2 Avoid non-const
global variables
I.13 Do not pass an array as a single pointer
I.27 For stable library ABI, consider the Pimpl idiom
F.4 If a function may have to be evaluated at compile-time, declare it constexpr
F.6 If your function may not throw, declare it noexcept
F.15 Prefer simple and conventional ways of passing information
F.16 For “in” parameters, pass cheaply-copied types by value and others by reference to const
F.19 For “forward” parameters, pass by TP&&
and only std::forward
the parameter
F.17 For “in-out” parameters, pass by reference to non-const
F.20 For “out” output values, prefer return values to output parameters
F.21 To return multiple “out” values, prefer returning a struct or tuple
F.42 Return a T*
to indicate a position (only)
F.44 Return a T&
when copy is undesirable and “returning no object” isn’t needed
F.48 Don’t return std::move(local)
F.46 int
is the return type for main()
F.51 Where there is a choice, prefer default arguments over overloading
F.55 Don’t use va_arg
arguments
C.1 Organize related data into structures (struct
s or class
es)
C.2 Use class
if the class has an invariant; use struct
if the data members can vary independently
C.3 Represent the distinction between an interface and an implementation using a class
C.4 Make a function a member only if it needs direct access to the representation of a class
C.5 Place helper functions in the same namespace as the class they support
C.7 Don’t define a class
or enum
and declare a variable of its type in the same statement
C.8 Use class
rather than struct
if any member is non-public
C.9 Minimize exposure of members
C.10 Prefer concrete types over class hierarchies
C.11 Make concrete types regular
C.20 If you can avoid defining any default operations, do
C.21 If you define or =delete
any default operation, define or =delete
them all
C.22 Make default operations consistent
C.41 A constructor should create a fully initialized object
C.42 If a constructor cannot construct a valid object, throw an exception
C.43 Ensure that a copyable (value type) class has a default constructor
C.46 By default, declare single-argument constructors explicit
C.47 Define and initialize member variables in the order of member declaration
C.48 Prefer in-class initializers to member initializers in constructors for constant initializers
C.49 Prefer initialization to assignment in constructors
C.51 Use delegating constructors to represent common actions for all constructors of a class
C.67 A polymorphic class should suppress copying
C.30 Define a destructor if a class needs an explicit action at object destruction
C.31 All resources acquired by a class must be released by the class’s destructor
C.32 If a class has a raw pointer (T*
) or reference (T&
), consider whether it might be owning
C.33 If a class has an owning pointer member, define a destructor
C.35 A base class destructor should be either public and virtual, or protected and non-virtual
C.80 Use =default
if you have to be explicit about using the default semantics
C.81 Use =delete
when you want to disable default behavior (without wanting an alternative)
C.82 Don’t call virtual functions in constructors and destructors
C.86 Make ==
symmetric with respect to operand types and noexcept
C.87 Beware of ==
on base classes
C.120 Use class hierarchies to represent concepts with inherent hierarchical structure (only)
C.121 If a base class is used as an interface, make it an abstract class
C.126 An abstract class typically doesn’t need a constructor
C.128 Virtual functions should specify exactly one of virtual
, override
, or final
C.132 Don’t make a function virtual
without reason
C.131 Avoid trivial getters and setters
C.134 Ensure all non-const
data members have the same access level
C.135 Use multiple inheritance to represent multiple distinct interfaces
C.138 Create an overload set for a derived class and its bases with using
C.140 Do not provide different default arguments for a virtual function and an overrider
C.146 Use dynamic_cast
where class hierarchy navigation is unavoidable
C.152 Never assign a pointer to an array of derived class objects to a pointer to its base
C.167 Use an operator for an operation with its conventional meaning
C.161 Use nonmember functions for symmetric operators
C.164 Avoid implicit conversion operators
C.162 Overload operations that are roughly equivalent
C.163 Overload only for operations that are roughly equivalent
C.168 Define overloaded operators in the namespace of their operands
C.180 Use union
s to save memory
C.182 Use anonymous union
s to implement tagged unions
Enum.1 Prefer enumerations over macros
Enum.2 Use enumerations to represent sets of related named constants
Enum.3 Prefer enum classes over “plain” enums
Enum.5 Don’t use ALL_CAPS
for enumerators
Enum.6 Avoid unnamed enumerations
Enum.7 Specify the underlying type of an enumeration only when necessary
Enum.8 Specify enumerator values only when necessary
R.3 A raw pointer (a T*
) is non-owning
R.4 A raw reference (a T&
) is non-owning
R.5 Prefer scoped objects, don’t heap-allocate unnecessarily
R.10 Avoid malloc()
and free()
R.11 Avoid calling new
and delete
explicitly
R.12 Immediately give the result of an explicit resource allocation to a manager object
R.13 Perform at most one explicit resource allocation in a single expression statement
R.20 Use unique_ptr
or shared_ptr
to represent ownership
R.21 Prefer unique_ptr
over shared_ptr
unless you need to share ownership
R.22 Use make_shared()
to make shared_ptr
s
R.23 Use make_unique()
to make unique_ptr
s
R.24 Use std::weak_ptr
to break cycles of shared_ptr
s
R.30 Take smart pointers as parameters only to explicitly express lifetime semantics
R.37 Do not pass a pointer or reference obtained from an aliased smart pointer
ES.1 Prefer the standard library to other libraries and to “handcrafted code”
ES.2 Prefer suitable abstractions to direct use of language features
ES.6 Declare names in for-statement initializers and conditions to limit scope
ES.7 Keep common and local names short, and keep uncommon and nonlocal names longer
ES.8 Avoid similar-looking names
ES.10 Declare one name (only) per declaration
ES.11 Use auto
to avoid redundant repetition of type names
ES.12 Do not reuse names in nested scopes
ES.20 Always initialize an object
ES.21 Don’t introduce a variable (or constant) before you need to use it
ES.22 Don’t declare a variable until you have a value to initialize it with
ES.23 Prefer the {}
-initializer syntax
ES.26 Don’t use a variable for two unrelated purposes
ES.28 Use lambdas for complex initialization, especially of const
variables
ES.40 Avoid complicated expressions
ES.41 If in doubt about operator precedence, parenthesize
ES.42 Keep use of pointers simple and straightforward
ES.45 Avoid “magic constants”; use symbolic constants
ES.55 Avoid the need for range checking
ES.47 Use nullptr
rather than 0
or NULL
ES.61 Delete arrays using delete[]
and non-arrays using delete
ES.65 Don’t dereference an invalid pointer
ES.43 Avoid expressions with undefined order of evaluation
ES.44 Don’t depend on order of evaluation of function arguments
ES.49 If you must use a cast, use a named cast
ES.78 Don’t rely on implicit fallthrough in switch
statements
ES.79 Use default
to handle common cases (only)
ES.100 Don’t mix signed and unsigned arithmetic
ES.101 Use unsigned types for bit manipulation
ES.102 Use signed types for arithmetic
ES.106 Don’t try to avoid negative values by using unsigned
Per.7 Design to enable optimization
Per.10 Rely on the static type system
Per.11 Move computation from run time to compile-time
Per.19 Access memory predictably
CP.1 Assume that your code will run as part of a multi-threaded program
CP.3 Minimize explicit sharing of writable data
CP.4 Think in terms of tasks, rather than threads
CP.8 Don’t try to use volatile
for synchronization
CP.9 Whenever feasible use tools to validate your concurrent code
CP.20 Use RAII, never plain lock()/unlock()
CP.21 Use std::lock()
or std::scoped_lock
to acquire multiple mutexe
s
CP.22 Never call unknown code while holding a lock (e.g., a callback)
CP.23 Think of a joining thread
as a scoped container
CP.24 Think of a thread
as a global container
CP.25 Prefer std::jthread
over std::thread
CP.42 Don’t wait
without a condition
CP.31 Pass small amounts of data between threads by value, rather than by reference or pointer
CP.32 To share ownership between unrelated threads
use shared_ptr
CP.40 Minimize context switching
CP.41 Minimize thread creation and destruction
CP.43 Minimize time spent in a critical section
CP.44 Remember to name your lock_guards
and unique_locks
CP.100 Don’t use lock-free programming unless you absolutely have to
CP.101 Distrust your hardware/compiler combination
CP.102 Carefully study the literature
E.3 Use exceptions for error handling only
E.14 Use purpose-designed user-defined types as exceptions (not built-in types)
E.15 Catch exceptions from a hierarchy by reference
E.13 Never throw while being the direct owner of an object
E.30 Don’t use exception specifications
E.31 Properly order your catch-clauses
Con.1 By default, make objects immutable
Con.2 By default, make member functions const
Con.3 By default, pass pointers and references to consts
Con.4 Use const
to define objects with values that do not change after construction
Con.5 Use constexpr
for values that can be computed at compile-time
T.1 Use templates to raise the level of abstraction of code
T.2 Use templates to express algorithms that apply to many argument types
T.3 Use templates to express containers and ranges
T.40 Use function objects to pass operations to algorithms
T.42 Use template aliases to simplify notation and hide implementation details
T.43 Prefer using
over typedef
for defining aliases
T.44 Use function templates to deduce class template argument types (where feasible)
T.46 Require template arguments to be at least Regular
or SemiRegular
T.47 Avoid highly visible unconstrained templates with common names
T.48 If your compiler does not support concepts, fake them with enable_if
T.60 Minimize a template’s context dependencies
T.61 Do not over-parameterize members
T.62 Place non-dependent class template members in a non-templated base class
T.80 Do not naively templatize a class hierarchy
T.83 Do not declare a member function template virtual
T.140 Name all operations with potential for reuse
T.141 Use an unnamed lambda if you need a simple function object in one place only
T.143 Don’t write unintentionally nongeneric code
T.144 Don’t specialize function templates
CPL.2 If you must use C, use the common subset of C and C++, and compile the C code as C++
CPL.3 If you must use C for interfaces, use C++ in the calling code using such interfaces
SF.2 A .h
file may not contain object definitions or non-inline function definitions
SF.5 A .cpp
file must include the .h
file(s) that defines its interface
SF.8 Use #include
guards for all .h
files
SF.9 Avoid cyclic dependencies among source files
SF.10 Avoid dependencies on implicitly #included
names
SF.11 Header files should be self-contained
SF.7 Don’t write using namespace
at global scope in a header file
SF.20 Use namespaces
to express logical structure
SF.21 Don’t use an unnamed (anonymous) namespace in a header
SF.22 Use an unnamed (anonymous) namespace for all internal/nonexported entities
SL.con.1 Prefer using STL array
or vector
instead of a C-array
SL.con.2 Prefer using STL vector
by default unless you have a reason to use a different container
SL.str.1 Use std::string
to own character sequences
SL.str.2 Use std::string_view
to refer to character sequences
SL.str.4 Use char*
to refer to a single character
SL.str.5 Use std::byte
to refer to byte values that do not necessarily represent characters
SL.str.12 Use the s
suffix for string literals meant to be standard-library strings
SL.io.1 Use character-level input only when you have to
SL.io.2 When reading, always consider ill-formed input
SL.io.3 Prefer iostreams for I/O
SL.io.10 Unless you use printf-
family functions call ios_base::sync_with_stdio(false)
A.1 Separate stable code from less stable code
A.2 Express potentially reusable parts as a library
A.4 There should be no cycles among libraries
NR.1 Don’t insist that all declarations should be at the top of a function
NR.2 Don’t insist to have only a single return-statement in a function
NR.4 Don’t insist on placing each class declaration in its own source file
NR.5 Don’t use two-phase initialization
NR.6 Don’t place all cleanup actions at the end of a function and goto exit