C++ coding standards based on the C++ Core Guidelines (isocpp.github.io). Use when writing, reviewing, or refactoring C++ code to enforce modern, safe, and idiomatic practices.
Comprehensive coding standards for modern C++ (C++17/20/23) derived from the C++ Core Guidelines. Enforces type safety, resource safety, immutability, and clarity.
enum vs enum class, raw pointer vs smart pointer)These themes recur across the entire guidelines and form the foundation:
const/constexpr; mutability is the exception| Rule | Summary |
|---|---|
| P.1 | Express ideas directly in code |
| P.3 | Express intent |
| P.4 | Ideally, a program should be statically type safe |
| P.5 | Prefer compile-time checking to run-time checking |
| P.8 | Don't leak any resources |
| P.10 | Prefer immutable data to mutable data |
| I.1 | Make interfaces explicit |
| I.2 | Avoid non-const global variables |
| I.4 | Make interfaces precisely and strongly typed |
| I.11 | Never transfer ownership by a raw pointer or reference |
| I.23 | Keep the number of function arguments low |
// P.10 + I.4: Immutable, strongly typed interface
struct Temperature {
double kelvin;
};
Temperature boil(const Temperature& water);
// Weak interface: unclear ownership, unclear units
double boil(double* temp);
// Non-const global variable
int g_counter = 0; // I.2 violation
| Rule | Summary |
|---|---|
| F.1 | Package meaningful operations as carefully named functions |
| F.2 | A function should perform a single logical operation |
| F.3 | Keep functions short and simple |
| F.4 | If a function might be evaluated at compile time, declare it constexpr |
| F.6 | If your function must not throw, declare it noexcept |
| F.8 | Prefer pure functions |
| F.16 | For "in" parameters, pass cheaply-copied types by value and others by const& |
| F.20 | For "out" values, prefer return values to output parameters |
| F.21 | To return multiple "out" values, prefer returning a struct |
| F.43 | Never return a pointer or reference to a local object |
// F.16: Cheap types by value, others by const&
void print(int x); // cheap: by value
void analyze(const std::string& data); // expensive: by const&
void transform(std::string s); // sink: by value (will move)
// F.20 + F.21: Return values, not output parameters
struct ParseResult {
std::string token;
int position;
};
ParseResult parse(std::string_view input); // GOOD: return struct
// BAD: output parameters
void parse(std::string_view input,
std::string& token, int& pos); // avoid this
// F.4 + F.8: Pure, constexpr where possible
constexpr int factorial(int n) noexcept {
return (n <= 1) ? 1 : n * factorial(n - 1);
}
static_assert(factorial(5) == 120);
T&& from functions (F.45)va_arg / C-style variadics (F.55)const T which inhibits move semantics (F.49)| Rule | Summary |
|---|---|
| C.2 | Use class if invariant exists; struct if data members vary independently |
| C.9 | Minimize exposure of members |
| C.20 | If you can avoid defining default operations, do (Rule of Zero) |
| C.21 | If you define or =delete any copy/move/destructor, handle them all (Rule of Five) |
| C.35 | Base class destructor: public virtual or protected non-virtual |
| C.41 | A constructor should create a fully initialized object |
| C.46 | Declare single-argument constructors explicit |
| C.67 | A polymorphic class should suppress public copy/move |
| C.128 | Virtual functions: specify exactly one of virtual, override, or final |
// C.20: Let the compiler generate special members
struct Employee {
std::string name;
std::string department;
int id;
// No destructor, copy/move constructors, or assignment operators needed
};
// C.21: If you must manage a resource, define all five
class Buffer {