P.1: Express ideas directly in code |
Replace anonymous int by functional EventID |
Yes |
P.2: Write in ISO Standard C++ |
No Visual/GNU C++ extensions |
Yes |
P.3: Express intent |
Code for the other devs, Self-explanatory code does not need comments |
Yes |
P.4: Ideally, a program should be statically type safe |
Replace union -> variant and int array[5] -> span |
Yes |
P.5: Prefer compile-time checking to run-time checking |
Replace assert by static_assert when possible |
Yes |
P.6: What cannot be checked at compile time should be checkable at run time |
Use span |
Developer decides, reviewer may propose to use span |
P.7: Catch run-time errors early |
??? (please provide a summary) |
Yes |
P.8: Don't leak any resources |
Use RAII |
Yes |
P.9: Don't waste time or space |
C++ => Do not sacrify performance |
Yes |
P.10: Prefer immutable data to mutable data |
Use constants when possible (see section Constants and Immutability) |
Ok |
I.1: Make interfaces explicit |
Names (of function/variable...) must convey semantic (no surprise when used) |
Yes |
I.2 Avoid global variables |
Global variable hide dependencies (except const ). Put log level in an object. |
Yes but except specific cases (justify) |
I.3: Avoid singletons |
Singleton is a global variable => Singleton also hides dependencies |
Yes but as above (see Dependency Inversion) |
I.4: Make interfaces precisely and strongly typed |
No anonymous int or void* (no error-prone casting). Use instead variant , base class, template (and C++17 Concept). |
Yes. Use setter (SBE) instead of many default arg. |
I.5: State preconditions (if any) |
Provide comments for preconditions and use Expects() , static_assert() , assert() , if() ... |
Yes |
I.6: Prefer Expects() for expressing preconditions |
Expects() = Make it clear + Enable analysis tools |
No Expects() on release => assert() static_assert() . Integrity check => if() |
I.7: State postconditions |
Same as for preconditions |
Yes |
I.8: Prefer Ensures() for expressing postconditions |
Same as for preconditions |
No, same remark as I.6 |
I.9: If an interface is a template, document its parameters using concepts |
Use C++17 Concepts (available in gcc-6.1). In comments if not yet supported. |
No, Document in Doxygen if not supported yes) |
I.10: Use exceptions to signal a failure to perform a required task |
Prevent error silence because system may become unexpected => Throw exception or return error status (or a pair {result + error}). Exceptions in framework. Logs in application |
Yes |
I.11: Never transfer ownership by a raw pointer (T*) |
Avoid ownnership transfer. => Use smart_pointer(unique_ptr or shared_ptr) to pass ownership. => Use owner(GSL) in older code. |
Yes |
I.12: Declare a pointer that must not be null as not_null |
To avoid nullptr deferencing errors and redundant checks for nullptr. |
Yes |
I.13: Do not pass an array as a single pointer |
Use span and string_span to avoid range error |
Developer decides, reviewer may propose to use span |
I.22: Avoid complex initialization of global objects |
Avoid globals(namespace scope) object altogether |
Yes |
I.23: Keep the number of function arguments low |
Avoid more than 8 arguments. Group arguments into meaningfull objects or use default arguments |
Yes |
I.24: Avoid adjacent unrelated parameters of the same type |
Pass object representing a range (span). Define struct as parameter type |
Yes |
I.25: Prefer abstract classes as interfaces to class hierarchies |
Use abstract class with pure virtual function |
Yes |
I.26: If you want a cross-compiler ABI, use a C-style subset |
Different compilers implement different binary layouts |
Not concerned |
F.1: "Package" meaningful operations as carefully named functions |
functions can be easier to reuse than objects |
Yes |
F.2: A function should perform a single logical operation |
simpler to understand, test and reuse |
Yes |
F.4: If a function may have to be evaluated at compile time, declare it constexpr |
contexpr is needed to tell the compiler to allow compile-time evaluation |
Yes |
F.18: For "consume" parameters, pass by X&& and std::move the parameter |
avoids a deep copy and sometimes a copy would not have been possible (for ex. std::ofstream) |
Yes |
F.60: Prefer T* over T& when "no argument" is a valid option |
A pointer (T*) can be a nullptr and a reference (T&) cannot |
Yes |
[F.42: Return a T* to indicate a position (only)] (https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#f42-return-a-t-to-indicate-a-position-only) |
That's what pointers are good for. Returning a T* to transfer ownership is a misuse |
Yes |
[F.52: Prefer capturing by reference in lambdas that will be used locally, including passed to algorithms] (https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#f52-prefer-capturing-by-reference-in-lambdas-that-will-be-used-locally-including-passed-to-algorithms) |
know capture options |
Yes |
F.16: For "in" parameters, pass cheaply-copied types by value and others by reference to const |
Same semantics for both, better performances |
Yes |
F.21: To return multiple "out" values, prefer returning a tuple or struct |
It is self documenting, and std::ignore can be sued |
To bench |
F.26: Use a unique_ptr to transfer ownership where a pointer is needed |
Use std::unique_ptr to ransfer ownership |
Yes if code is C++11 only |
F.43: Never (directly or indirectly) return a pointer to a local object |
Do not return pointers to local object |
Yes |
F.44: Return a T& when copy is undesirable and "returning no object" isn't needed |
Return T& when copy is undesirable |
Yes |
F.45: Don't return a T&& |
Do not return T&&, it makes no sense |
Yes |
F.46: int is the return type for main() |
void main() is not C++ |
Yes |
F.47: Return T& from assignment operators |
Ensures consistency with std |
Yes |
F.50: Use a lambda when a function won't do (to capture local variables, or to write a local function) |
Same as a function object but more simple to write |
Yes |
F.51: Where there is a choice, prefer default arguments over overloading |
Limits code duplication and behavior divergence |
No |
F.53: Avoid capturing by reference in lambdas that will be used nonlocally, including returned, stored on the heap, or passed to another thread |
To maintain proper lifecycle |
Yes |
F.54: If you capture this, capture all variables explicitly (no default capture) |
Default capture does no behave the same for local variable and data members |
To bench |
C.1: Organize related data into structures (structs or classes) |
Ex: x and y i n a class "Point" |
OK |
C.2: Use class if the class has an invariant; use struct if the data members can vary independently |
Readability, hints at invariants |
OK |
C.3: Represent the distinction between an interface and an implementation using a class |
??? |
Ok on principle |
C.4: Make a function a member only if it needs direct access to the representation of a class |
Free function should not be tied to a class for no reason |
OK |
C.5: Place helper functions in the same namespace as the class they support |
Profit from argument dependent lookup |
OK |
C.7: Don't define a class or enum and declare a variable of its type in the same statement |
Useless and confusing for readers |
OK |
C.8: use class rather that struct if any member is non-public |
Hint readers |
OK |
C.9: minimize exposure of members |
Improves encapsulation |
OK |
C.10 Prefer a concrete type over more complicated classes |
More simple than a class hierarchy |
Unclear |
C.11: Make concrete types regular |
Thats is, behave with a value semantics. Easier to use. |
Unclear |
C.20: If you can avoid defining default operations, do |
Shorter code |
Yes, and do not reimplement defaults |
C.21: If you define or =delete any default operation, define or =delete them all |
To ensure proper semantics are used |
Yes |
C.22: Make default operations consistent |
Doing otherwise would be most confusing |
Yes |
C.30: Define a destructor if a class needs an explicit action at object destruction |
When something must be done at destruction, the destructor must do it |
Yes |
C.31: All resources acquired by a class must be released by the class's destructor |
Basis of RAII |
Yes |
C.32: If a class has a raw pointer (T*) or reference (T&), consider whether it might be owning |
Annotate pointer as owning or not |
OK but avoid owning reference |
C.33: If a class has an owning pointer member, define a destructor |
If using pointers as members, protect from leak/copy |
OK |
C.34: If a class has an owning reference member, define a destructor |
Same as for pointer |
Prefer avoid owning reference, else Yes |
C.35: A base class destructor should be either public and virtual, or protected and nonvirtual |
Avoid leak of derived classes members |
Prefer avoid owning reference, else Yes |
C.36: A destructor may not fail |
RAII safe |
OK |
C.37: Make destructors noexcept |
Be explicit on exception absence |
OK |
C.40: Define a constructor if a class has an invariant |
In Out principle |
OK |
C.41: A constructor should create a fully initialized object |
Be safe with invariant and public interface |
OK |
C.42: If a constructor cannot construct a valid object, throw an exception |
Avoid objects in crashed state |
OK |
C.43: Ensure that a class has a default constructor |
Allow default object whenever possible |
For value classes |
C.44: Prefer default constructors to be simple and non-throwing |
Be safe with default constructors |
OK |
C.45: Don't define a default constructor that only initializes data members; use in-class member initializers instead |
Less code better |
OK |
C.46: By default, declare single-argument constructors explicit |
Avoid false conversions |
OK |
C.47: Define and initialize member variables in the order of member declaration |
Respect members order |
OK |