google-cpp-style
Use when writing or reviewing C++ under Google's C++ style conventions, including headers, naming, classes, functions, ownership, exceptions, and formatting. Do not use as a general C++ language tutor
SKILL.mdskills/google-cpp-style/SKILL.md
GitHubGoogle C++ Style Guide
Apply this guidance to the actual project. Repository requirements and newer authoritative guidance take precedence.
C++ Version
Currently, code should target C++20, i.e., should not use C++23 features. The C++ version targeted by this guide will advance (aggressively) over time.
Self-contained Headers
Header files should be self-contained (compile on their own) and
end in .h. Non-header files that are meant for inclusion
should end in .inc and be used sparingly.
All header files should be self-contained. Users and refactoring
tools should not have to adhere to special conditions to include the
header. Specifically, a header should
have header guards and include all
other headers it needs.
The #define Guard
All header files should have #define guards to
prevent multiple inclusion. The format of the symbol name
should be
<PROJECT>_<PATH>_<FILE>_H_.
Include What You Use
If a source or header file refers to a symbol defined elsewhere,
the file should directly include a header file which properly intends
to provide a declaration or definition of that symbol. It should not
include header files for any other reason.
Do not rely on transitive inclusions. This allows people to remove
no-longer-needed #include statements from their headers without
breaking clients. This also applies to related headers
foo.ccshould includebar.hif it uses a symbol from it even iffoo.hincludesbar.h.
Forward Declarations
Avoid using forward declarations where possible. Instead, include the headers you need. Do not use forward declarations of entities that your project does not own.
Names and Order of Includes
Include headers in the following order: Related header, C system headers, C++ standard library headers, other libraries' headers, your project's headers. Separate each non-empty group with one blank line. Within each section the includes should be ordered alphabetically. Note that older code might not conform to this rule and should be fixed when convenient.
Namespaces
With few exceptions, place code in a namespace. Namespaces
should have unique names based on the project name, and possibly
its path. Do not use using-directives (e.g.,
using namespace foo). Do not use
inline namespaces. For unnamed namespaces, see
Internal Linkage.
Internal Linkage
When definitions in a .cc file do not need to be
referenced outside that file, give them internal linkage by placing
them in an unnamed namespace or declaring them static.
Do not use either of these constructs in .h files.
Local Variables
Place a function's variables in the narrowest scope possible, and initialize variables in the declaration.
Static and Global Variables
Objects with static storage duration are forbidden unless they are trivially destructible. Informally this means that the destructor does not do anything, even taking member and base destructors into account. More formally it means that the type has no user-defined or virtual destructor and that all bases and non-static members are trivially destructible. Static function-local variables may use dynamic initialization. Use of dynamic initialization for static class member variables or variables at namespace scope is discouraged, but allowed in limited circumstances.
thread_local Variables
thread_local variables that aren't declared inside a function
must be initialized with a true compile-time constant,
and this must be enforced by using the
constinit
attribute. Prefer
thread_local over other ways of defining thread-local data.
Doing Work in Constructors
Avoid virtual method calls in constructors, and avoid
initialization that can fail if you can't signal an error.
Constructors should never call virtual functions. If appropriate
for your code ,
terminating the program may be an appropriate error handling
response. Otherwise, consider a factory function
or Init() method as described in
TotW #42
.
Avoid Init() methods on objects with
no other states that affect which public methods may be called
(semi-constructed objects of this form are particularly hard to work
with correctly).
Implicit Conversions
Do not define implicit conversions. Use the explicit
keyword for conversion operators and single-argument
constructors.
Type conversion operators, and constructors that are
callable with a single argument, must be marked
explicit in the class definition. As an
exception, copy and move constructors should not be
explicit, since they do not perform type
conversion.
Constructors that cannot be called with a single argument
may omit explicit. Constructors that
take a single std::initializer_list parameter should
also omit explicit, in order to support copy-initialization
(e.g., MyType m = {1, 2};).
Copyable and Movable Types
A class's public API must make clear whether the class is copyable,
move-only, or neither copyable nor movable. Support copying and/or
moving if these operations are clear and meaningful for your type.
Every class's public interface must make clear which copy and move
operations the class supports. This should usually take the form of explicitly
declaring and/or deleting the appropriate operations in the public
section of the declaration.
Specifically, a copyable class should explicitly declare the copy
operations, a move-only class should explicitly declare the move operations, and
a non-copyable/movable class should explicitly delete the copy operations. A
copyable class may also declare move operations in order to support efficient
moves. Explicitly declaring or deleting all four copy/move operations is
permitted, but not required. If you provide a copy or move assignment operator,
you must also provide the corresponding constructor.
A type should not be copyable/movable if the meaning of
copying/moving is unclear to a casual user, or if it incurs unexpected
costs. Move operations for copyable types are strictly a performance
optimization and are a potential source of bugs and complexity, so
avoid defining them unless they are significantly more efficient than
the corresponding copy operations. If your type provides copy operations, it is
recommended that you design your class so that the default implementation of
those operations is correct. Remember to review the correctness of any
defaulted operations as you would any other code.
Structs vs. Classes
Use a struct only for passive objects that
carry data; everything else is a class.
structs should be used for passive objects that carry
data, and may have associated constants. All fields must be public. The
struct type itself must not have invariants that imply relationships between
different fields, since direct user access to those fields may
break those invariants, but users of a struct may have requirements and
guarantees on particular uses of it. Constructors, destructors, and helper
methods may be present; however, these methods must not require or enforce
any invariants.
If more functionality or invariants are required, or struct has wide visibility and expected to
evolve, then a class is more appropriate. If in doubt, make it a class.
Inheritance
Composition is often more appropriate than inheritance.
When using inheritance, make it public.
Explicitly annotate overrides of virtual functions or virtual
destructors with exactly one of an override or (less
frequently) final specifier. Do not
use virtual when declaring an override.
Rationale: A function or destructor marked
override or final that is
not an override of a base class virtual function will
not compile, and this helps catch common errors. The
specifiers serve as documentation; if no specifier is
present, the reader has to check all ancestors of the
class in question to determine if the function or
destructor is virtual or not.
Access Control
Make classes' data members private, unless they are
constants. This simplifies reasoning about invariants, at the cost
of some easy boilerplate in the form of accessors (usually const) if necessary.
Inputs and Outputs
Prefer using return values over output parameters:
they improve readability, and often provide the same or better performance.
See
TotW #176.
Prefer to return by value or, failing that, return by reference.
Avoid returning a raw pointer unless it can be null.
Parameters are either inputs to the function, outputs from the
function, or both. Non-optional input parameters should usually be values
or const references, while non-optional output and
input/output parameters should usually be references (which cannot be null).
Generally, use std::optional to represent optional by-value
inputs, and use a const pointer when the non-optional form would
have used a reference. Use non-const pointers to represent
optional outputs and optional input/output parameters.
Avoid defining functions that require a reference parameter to outlive the call.
In some cases reference parameters can bind to temporaries, leading to lifetime
bugs. Instead, find a way to eliminate the lifetime requirement
(for example, by copying the parameter), or pass retained parameters by
pointer and document the lifetime and non-null requirements.
See TotW 116 for more.
Write Short Functions
Prefer small and focused functions.
Function Overloading
Use overloaded functions (including constructors) only if a reader looking at a call site can get a good idea of what is happening without having to first figure out exactly which overload is being called. You may overload a function when there are no semantic differences between variants. These overloads may vary in types, qualifiers, or argument count. However, a reader of such a call must not need to know which member of the overload set is chosen, only that something from the set is being called.
Default Arguments
Default arguments are allowed on non-virtual functions
when the default is guaranteed to always have the same
value. Follow the same restrictions as for function overloading, and
prefer overloaded functions if the readability gained with
default arguments doesn't outweigh the downsides below.
Default arguments are banned on virtual functions, where
they don't work properly, and in cases where the specified
default might not evaluate to the same value depending on
when it was evaluated. (For example, don't write void f(int n = counter++);.)
Ownership and Smart Pointers
Prefer to have single, fixed owners for dynamically
allocated objects. Prefer to transfer ownership with smart
pointers.
Do not design your code to use shared ownership
without a very good reason. One such reason is to avoid
expensive copy operations, but you should only do this if
the performance benefits are significant, and the
underlying object is immutable (i.e.,
std::shared_ptr<const Foo>). If you
do use shared ownership, prefer to use
std::shared_ptr.
Exceptions
We do not use C++ exceptions.
This prohibition also applies to exception handling related
features such as std::exception_ptr and
std::nested_exception.
Run-Time Type Information (RTTI)
Avoid using run-time type information (RTTI). RTTI has legitimate uses but is prone to abuse, so you must be careful when using it. You may use it freely in unit tests, but avoid it when possible in other code. In particular, think twice before using RTTI in new code. If you find yourself needing to write code that behaves differently based on the class of an object, consider one of the following alternatives to querying the type:
- Virtual methods are the preferred way of executing different code paths depending on a specific subclass type. This puts the work within the object itself.
- If the work belongs outside the object and instead in some processing code, consider a double-dispatch solution, such as the Visitor design pattern. This allows a facility outside the object itself to determine the type of class using the built-in type system. Do not hand-implement an RTTI-like workaround. The arguments against RTTI apply just as much to workarounds like class hierarchies with type tags. Moreover, workarounds disguise your true intent.
Casting
Use C++-style casts
like static_cast<float>(double_value), or brace
initialization for conversion of arithmetic types like
int64_t y = int64_t{1} << 42. Do not use
cast formats like (int)x unless the cast is to
void. You may use cast formats like T(x) only when
T is a class type.
Use of const
In APIs, use const whenever it makes sense.
constexpr is a better choice for some uses of
const.
All of a class's const operations should be safe
to invoke concurrently with each other. If that's not feasible, the class must
be clearly documented as "thread-unsafe".
Use of constexpr, constinit, and consteval
Use constexpr to define true
constants or to ensure constant initialization.
Use constinit to ensure constant
initialization for non-constant variables.
Integer Types
Of the built-in C++ integer types, the only one used
is
int. If a program needs an integer type of a
different size, use an exact-width integer type from
<stdint.h>, such as
int16_t. If you have a
value that could ever be greater than or equal to 2^31,
use a 64-bit type such as int64_t.
Keep in mind that even if your value won't ever be too large
for an int, it may be used in intermediate
calculations which may require a larger type. When in doubt,
choose a larger type.
You should not use the unsigned integer types such as
uint32_t, unless there is a valid
reason such as representing a bit pattern rather than a
number, or you need defined overflow modulo 2^N. In
particular, do not use unsigned types to say a number
will never be negative. Instead, use
assertions for this.
Preprocessor Macros
Avoid defining macros, especially in headers; prefer
inline functions, enums, and const variables.
Name macros with a project-specific prefix. Do not use
macros to define pieces of a C++ API.
Exporting macros from headers (i.e., defining them in a header
without #undefing them before the end of the header)
is extremely strongly discouraged. If you do export a macro from a
header, it must have a globally unique name. To achieve this, it
must be named with a prefix consisting of your project's namespace
name (but upper case).
0 and nullptr/NULL
Use nullptr for pointers, and '\0' for chars (and
not the 0 literal).
Type Deduction (including auto)
Use type deduction only if it makes the code clearer to readers who aren't familiar with the project, or if it makes the code safer. Do not use it merely to avoid the inconvenience of writing an explicit type.
Concepts and Constraints
Use concepts sparingly.
In general, concepts and constraints should only be used in cases
where templates would have been used prior to C++20.
Avoid introducing new concepts in headers,
unless the headers are marked as internal to the library.
Do not define concepts that are not enforced by the compiler.
Prefer constraints over template metaprogramming, and
avoid the template<Concept T> syntax;
instead, use the requires(Concept<T>)
syntax.
Nonstandard Extensions
Nonstandard extensions to C++ may not be used unless otherwise specified. Do not use nonstandard extensions. You may use portability wrappers that are implemented using nonstandard extensions, so long as those wrappers are provided by a designated project-wide portability header.
Choosing Names
Give things names that make their purpose or intent understandable to a new reader, even someone on a different team than the owners. Do not worry about saving horizontal space as it is far more important to make your code immediately understandable by a new reader.
File Names
Filenames should be all lowercase and can include
underscores (_) or dashes (-).
Follow the convention that your
project uses. If there is no consistent
local pattern to follow, prefer "_".
Type Names
Type names start with a capital letter and have a capital
letter for each new word, with no underscores:
MyExcitingClass, MyExcitingEnum.
Variable Names
The names of variables (including function parameters) and data members are
snake_case (all lowercase, with underscores between words). Data members of classes
(but not structs) additionally have trailing underscores. For instance:
a_local_variable, a_struct_data_member,
a_class_data_member_.
Constant Names
Variables declared constexpr or const, and whose value is fixed for
the duration of the program, are named with a leading "k" followed
by mixed case. Underscores can be used as separators in the rare cases
where capitalization cannot be used for separation. For example:
const int kDaysInAWeek = 7;
const int kAndroid8_0_0 = 24; // Android 8.0.0
Function Names
Ordinarily, functions follow PascalCase:
start with a capital letter and have a capital letter for each new word.
Accessors and mutators (get and set functions) may be named like variables,
in snake_case. These often correspond to actual member variables,
but this is not required. For example, int count() and
void set_count(int count).
Namespace Names
Namespace names are snake_case (all lowercase, with underscores
between words).
Top-level namespaces must be globally unique and recognizable, so each one
should be owned by a single project or team, with a name based on the name of
that project or team. Usually, all code in the namespace should be under one or
more directories with the same name as the namespace.
Macro Names
Please see the description of macros; in general macros should not be used. However, if they are absolutely needed, then they should be named with all capitals and underscores, and with a project-specific prefix.
Function Declarations
Almost every function declaration should have comments immediately
preceding it that describe what the function does and how to use
it. These comments may be omitted only if the function is simple and
obvious (e.g., simple accessors for obvious properties of the class).
Private methods and functions declared in .cc files are not exempt.
Function comments should be written with an implied subject of
This function and should start with the verb phrase; for example,
"Opens the file", rather than "Open the file". In general, these comments do not
describe how the function performs its task. Instead, that should be
left to comments in the function definition.
Line Length
Each line of text in your code should be at most 80 characters long. A line may exceed 80 characters if it is
Looping and branching statements
- The components of the statement should be separated by single spaces (not line breaks).
- Inside the condition or iteration specifier, put one space (or a line break) between each semicolon and the next token, except if the token is a closing parenthesis or another semicolon.
- Inside the condition or iteration specifier, do not put a space after the opening parenthesis or before the closing parenthesis.
- Put any controlled statements inside blocks (i.e., use curly braces).
- Inside the controlled blocks, put one line break immediately after the
opening brace, and one line break immediately before the closing brace.
Empty loop bodies should use either an empty pair of braces or
continuewith no braces, rather than a single semicolon.