A condensed set of rules (drawn from the C++ Core Guidelines) that keep modern C++ safe, readable and fast.
Resource management
Types & interfaces
Make things
constby default — variables, parameters (const T&), member functions.Prefer
enum class,std::array/std::vector,std::string_view/std::spanfor views,std::optionalfor “maybe”.Mark single-argument constructors
explicit; mark overridesoverride; give polymorphic bases avirtualdestructor.Pass cheap types by value, others by
const&; return by value (move/elision make it cheap).Use strong types instead of
bool/intsoup:setTimeout(Seconds{5}), notsetTimeout(5).
Expressions & control
Initialise every variable at declaration; prefer
{}to catch narrowing.Use
autoto avoid repeating types, not to hide important ones.Prefer algorithms and range-for over index loops; prefer
std::ranges::versions in C++20.Use named casts (
static_cast) and minimise them; never C-style casts.Keep functions short and single-purpose; limit scope of variables (
if (auto x = …; cond)).
Tooling
| Tool | Why |
|---|---|
-Wall -Wextra -Wpedantic -Werror | Catch mistakes at compile time |
| ASan / UBSan / TSan | Catch memory errors, UB and races in tests |
clang-tidy | Static analysis, modernisation checks (modernize-*, cppcoreguidelines-*) |
clang-format | Consistent formatting, no style debates |
| CMake + a package manager (vcpkg/Conan) | Reproducible builds and dependencies |
| GoogleTest / Catch2 | Unit tests |
Idioms worth knowing
#include <iostream>
template <typename Derived>
struct Shape { // CRTP base
double area() const { return static_cast<const Derived&>(*this).areaImpl(); }
void describe() const { std::cout << "area " << area() << '\n'; }
};
struct Square : Shape<Square> {
double s;
explicit Square(double x) : s(x) {}
double areaImpl() const { return s * s; }
};
int main() { Square{3}.describe(); } // resolved at compile time, no vtablearea 9What is CRTP and why use it?