Google C++ Style Guide
- -Background
C++ is one of the main development languages used by @@ -64,10 +61,10 @@
Goals of the Style Guide
remember it. The benefit is measured relative to the codebase we would get without the rule, so a rule against a very harmful practice may still have a small benefit if people are unlikely to do it -anyway. This principle mostly explains the rules we don’t have, rather +anyway. This principle mostly explains the rules we don’t have, rather than the rules we do: for example,goto
contravenes many
of the following principles, but is already vanishingly rare, so the Style
-Guide doesn’t discuss it.
+Guide doesn’t discuss it.
Header Files
In general, every .cc
file should have an
associated .h
file. There are some common
-exceptions, such as unittests and
-small .cc
files containing just a
-main()
function.
.cc
files containing
+just a main()
function.
Correct use of header files can make a huge difference to the readability, size and performance of your code.
@@ -291,16 +287,16 @@Forward Declarations
Replacing an#include
with a forward
declaration can silently change the meaning of
code:
- // b.h: - struct B {}; - struct D : B {}; - - // good_user.cc: - #include "b.h" - void f(B*); - void f(void*); - void test(D* x) { f(x); } // calls f(B*) -+
// b.h: +struct B {}; +struct D : B {}; + +// good_user.cc: +#include "b.h" +void f(B*); +void f(void*); +void test(D* x) { f(x); } // calls f(B*) +If the
#include
was replaced with forward
decls for B
and D
,
test()
would call f(void*)
.
@@ -311,7 +307,7 @@ Forward Declarations
#include
ing the header.
Names and Order of Includes
.h
extension), e.g. <unistd.h>
,
+ .h
extension), e.g., <unistd.h>
,
<stdlib.h>
.<algorithm>
, <cstddef>
.Names and Order of Includes
dir/foo.cc
and
dir2/foo2.h
are usually in the same
-directory (e.g. base/basictypes_test.cc
and
+directory (e.g., base/basictypes_test.cc
and
base/basictypes.h
), but may sometimes be in different
directories too.
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.
+its path. Do not use using-directives (e.g.,
Prefer placing nonmember functions in a namespace; use completely global
-functions rarely. Do not use a class simply to group static functions. Static
+functions rarely. Do not use a class simply to group static members. Static
methods of a class should generally be closely related to instances of the
class or the class's static data.using namespace foo
). Do not use
inline namespaces. For unnamed namespaces, see
Unnamed Namespaces and
@@ -700,7 +696,7 @@ Unnamed Namespaces and Static
Nonmember, Static Member, and Global Functions
Nonmember, Static Member
can be either a static member or a nonmember function.
Nonmember functions should not depend on external
variables, and should nearly always exist in a namespace.
-Do not create classes only to group static member functions;
-this is no different than just giving the function names a
+Do not create classes only to group static members;
+this is no different than just giving the names a
common prefix, and such grouping is usually unnecessary anyway.
If you define a nonmember function and it is only @@ -741,7 +737,7 @@
Local Variables
possible. This makes it easier for the reader to find the declaration and see what type the variable is and what it was initialized to. In particular, initialization should -be used instead of declaration and assignment, e.g.: +be used instead of declaration and assignment, e.g.,:int i; i = f(); // Bad -- initialization separate from declaration. @@ -954,8 +950,8 @@Common patterns
collection, such as a set to search against or a lookup table, you cannot use the dynamic containers from the standard library as a static variable, since they have non-trivial destructors. Instead, consider a simple array of - trivial types, e.g. an array of arrays of ints (for a "map from int to - int"), or an array of pairs (e.g. pairs ofint
andconst + trivial types, e.g., an array of arrays of ints (for a "map from int to + int"), or an array of pairs (e.g., pairs of
int
andconst char*
). For small collections, linear search is entirely sufficient (and efficient, due to memory locality); consider using the facilities from @@ -975,7 +971,7 @@Common patterns
a type that you need to define yourself, give the type a trivial destructor and aconstexpr
constructor.If all else fails, you can create an object dynamically and never delete - it by using a function-local static pointer or reference (e.g. @@ -1053,7 +1049,7 @@static + it by using a function-local static pointer or reference (e.g.,
static const auto& impl = *new T(args...);
).thread_local Variables
thread_local
variables at class or namespace scope must be
-initialized with a true compile-time constant (i.e. they must have no
+initialized with a true compile-time constant (i.e., they must have no
dynamic initialization). To enforce this, thread_local
variables
at class or namespace scope must be annotated with
@@ -1147,7 +1143,7 @@
Implicit Conversions
users can define their own, by adding appropriate members to the class definition of the source or destination type. An implicit conversion in the source type is defined by a type conversion operator -named after the destination type (e.g.operator
+named after the destination type (e.g., operator
bool()
). An implicit conversion in the destination
type is defined by a constructor that can take the source type as
its only argument (or only argument with no default value).
@@ -1155,7 +1151,7 @@ Implicit Conversions
The explicit
keyword can be applied to a constructor
or (since C++11) a conversion operator, to ensure that it can only be
used when the destination type is explicit at the point of use,
-e.g. with a cast. This applies not only to implicit conversions, but to
+e.g., with a cast. This applies not only to implicit conversions, but to
C++11's list initialization syntax:
class Foo {
explicit Foo(int x, double y);
@@ -1202,8 +1198,11 @@ Implicit Conversions
it's intended to define an implicit conversion, or the author
simply forgot to mark it.
-
It's not always clear which type should provide the conversion,
- and if they both do, the code becomes ambiguous.
+Implicit conversions can lead to call-site ambiguities, especially
+ when there are bidirectional implicit conversions. This can be caused
+ either by having two types that both provide an implicit conversion,
+ or by a single type that has both an implicit constructor and an
+ implicit type conversion operator.
List initialization can suffer from the same problems if
the destination type is implicit, particularly if the
@@ -1216,17 +1215,21 @@ Implicit Conversions
explicit
in the class definition. As an
exception, copy and move constructors should not be
explicit
, since they do not perform type
-conversion. Implicit conversions can sometimes be necessary and
-appropriate for types that are designed to transparently wrap other
-types. In that case, contact
-your project leads to request
-a waiver of this rule.
+conversion.
+
+Implicit conversions can sometimes be necessary and appropriate for
+types that are designed to be interchangeable, for example when objects
+of two types are just different representations of the same underlying
+value. In that case, contact
+your project leads to request a waiver
+of this rule.
+
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};
).
+(e.g., MyType m = {1, 2};
).
Copyable and Movable Types
@@ -1256,7 +1259,7 @@ Copyable and Movable Types
copy constructor and the copy-assignment operator otherwise.
The copy/move constructors can be implicitly invoked by the compiler
-in some situations, e.g. when passing objects by value.
+in some situations, e.g., when passing objects by value.
Objects of copyable and movable types can be passed and returned by value,
@@ -1397,14 +1400,12 @@
Structs vs. Classes
defining.
structs
should be used for passive objects that carry
-data, and may have associated constants, but lack any functionality
-other than access/setting the data members. All fields must be public,
-and accessed directly rather than through getter/setter methods. The
+data, and may have associated constants. All fields must be public. The
struct must not have invariants that imply relationships between
-different fields, since direct user access to those fields may break
-those invariants. Methods should not provide behavior but should only
-be used to set up the data members, e.g., constructor, destructor,
-Initialize()
, Reset()
.
+different fields, since direct user access to those fields may
+break those invariants. 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, a
class
is more appropriate. If in doubt, make
@@ -1535,7 +1536,7 @@
Operator Overloading
Operator overloading can make code more concise and
intuitive by enabling user-defined types to behave the same
as built-in types. Overloaded operators are the idiomatic names
-for certain operations (e.g. ==
, <
,
+for certain operations (e.g., ==
, <
,
=
, and <<
), and adhering to
those conventions can make user-defined types more readable
and enable them to interoperate with libraries that expect
@@ -1563,7 +1564,7 @@
Operator Overloading
Finding the call sites for overloaded operators may
require a search tool that's aware of C++ syntax, rather
- than e.g. grep.
+ than e.g., grep.
If you get the argument type of an overloaded operator
wrong, you may get a different overload rather than a
@@ -1641,7 +1642,7 @@ Operator Overloading
Do not overload &&
, ||
,
,
(comma), or unary &
. Do not overload
-operator""
, i.e. do not introduce user-defined
+operator""
, i.e., do not introduce user-defined
literals. Do not use any such literals provided by others
(including the standard library).
@@ -1661,12 +1662,14 @@ Access Control
of some easy boilerplate in the form of accessors (usually const
) if necessary.
For technical
-reasons, we allow data members of a test fixture class in a .cc file to
+reasons, we allow data members of a test fixture class defined in a .cc file to
be protected
when using
Google
-Test).
+Test).
+If a test fixture class is defined outside of the .cc file it is used in, for example in a .h file,
+make data members private
.
Declaration Order
@@ -1682,7 +1685,7 @@ Declaration Order
kinds of declarations together, and generally prefer the
following order: types (including typedef
,
using
, and nested structs and classes),
-constants, factory functions, constructors, assignment
+constants, factory functions, constructors and assignment
operators, destructor, all other methods, data members.
Do not put large method definitions inline in the
@@ -1694,31 +1697,41 @@
Declaration Order
Functions
-Output Parameters
+
+Inputs and Outputs
The output of a C++ function is naturally provided via
-a return value and sometimes via output parameters.
+a return value and sometimes via output parameters (or in/out parameters).
Prefer using return values over output parameters: they
improve readability, and often provide the same or better
-performance. If output-only parameters are used,
-they should appear after input parameters.
+performance.
Parameters are either input to the function, output from the
-function, or both. Input parameters are usually values or
-const
references, while output and input/output
-parameters will be pointers to non-const
.
+function, or both. Input parameters should usually be values
+or const
references,
+while required (non-nullable) output and input/output parameters should
+usually be references. Generally, use absl::optional
to represent
+optional inputs, and non-const
pointers to represent
+optional outputs.
+
+
+Avoid defining functions that require a const
reference parameter
+to outlive the call, because const
reference parameters bind
+to temporaries. Instead, find a way to eliminate the lifetime requirement
+(for example, by copying the parameter), or pass it by const
+pointer and document the non-null requirement.
+
+
When ordering function parameters, put all input-only
parameters before any output parameters. In particular,
do not add new parameters to the end of the function just
because they are new; place new input-only parameters before
-the output parameters.
-
-This is not a hard-and-fast rule. Parameters that are
-both input and output (often classes/structs) muddy the
-waters, and, as always, consistency with related
-functions may require you to bend the rule.
+the output parameters. This is not a hard-and-fast rule. Parameters that
+are both input and output muddy the waters, and, as always,
+consistency with related functions may require you to bend the rule.
+Variadic functions may also require unusual parameter ordering.
Write Short Functions
@@ -1746,65 +1759,6 @@ Write Short Functions
it in several different contexts, consider breaking up
the function into smaller and more manageable pieces.
-Reference Arguments
-
-All parameters passed by lvalue reference must be labeled
-const
.
-
-
-In C, if a
-function needs to modify a variable, the parameter must
-use a pointer, eg int foo(int *pval)
. In
-C++, the function can alternatively declare a reference
-parameter: int foo(int &val)
.
-
-
-Defining a parameter as reference avoids ugly code like
-(*pval)++
. Necessary for some applications
-like copy constructors. Makes it clear, unlike with
-pointers, that a null pointer is not a possible
-value.
-
-
-References can be confusing, as they have value syntax
-but pointer semantics.
-
-
-Within function parameter lists all references must be
-const
:
-
-void Foo(const std::string &in, std::string *out);
-
-
-In fact it is a very strong convention in Google code
-that input arguments are values or const
-references while output arguments are pointers. Input
-parameters may be const
pointers, but we
-never allow non-const
reference parameters
-except when required by convention, e.g.,
-swap()
.
-
-However, there are some instances where using
-const T*
is preferable to const
-T&
for input parameters. For example:
-
-
- - You want to pass in a null pointer.
-
- - The function saves a pointer or reference to the
- input.
-
-
- Remember that most of the time input
-parameters are going to be specified as const
-T&
. Using const T*
instead
-communicates to the reader that the input is somehow
-treated differently. So if you choose const
-T*
rather than const T&
, do so
-for a concrete reason; otherwise it will likely confuse
-readers by making them look for an explanation that
-doesn't exist.
-
Function Overloading
Use overloaded functions (including constructors) only if a
@@ -1993,7 +1947,7 @@
Ownership and Smart Pointers
another.
"Smart" pointers are classes that act like pointers,
-e.g. by overloading the *
and
+e.g., by overloading the *
and
->
operators. Some smart pointer types
can be used to automate ownership bookkeeping, to ensure
these responsibilities are met.
@@ -2069,7 +2023,7 @@
Ownership and Smart Pointers
Shared ownership requires explicit bookkeeping at
run-time, which can be costly.
- In some cases (e.g. cyclic references), objects
+ In some cases (e.g., cyclic references), objects
with shared ownership may never be deleted.
Smart pointers are not perfect substitutes for
@@ -2094,7 +2048,7 @@ Ownership and Smart Pointers
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.
+underlying object is immutable (i.e.,
std::shared_ptr<const Foo>
). If you
do use shared ownership, prefer to use
std::shared_ptr
.
@@ -2131,19 +2085,7 @@ Other C++ Features
Rvalue References
-Use rvalue references to:
-
- - Define move constructors and move assignment operators.
-
- - Define overload sets with
- const& and && variants if you have evidence that this
- provides meaningfully better performance than passing by value,
- or if you're writing low-overhead generic code that needs to support
- arbitrary types. Beware combinatorial overload sets, that is, seldom
- overload more than one parameter.
-
- - Support 'perfect forwarding' in generic code.
-
+Use rvalue references only in certain special cases listed below.
Rvalue references
@@ -2201,23 +2143,32 @@
Rvalue References
-You may use rvalue references to define move constructors and move
-assignment operators (as described in
-Copyable and Movable Types). See the
-C++ Primer for more information about
-move semantics and std::move
.
-
-You may use rvalue references to define pairs of overloads, one taking
-Foo&&
and the other taking const Foo&
.
-Usually the preferred solution is just to pass by value, but an overloaded pair
-of functions sometimes yields better performance and is sometimes necessary in
-generic code that needs to support a wide variety of types. As always: if
-you're writing more complicated code for the sake of performance, make sure you
-have evidence that it actually helps.
-
-You may use forwarding references in conjunction with
-std::forward
,
-to support perfect forwarding.
+Do not use rvalue references (or apply the &&
+qualifier to methods), except as follows:
+
+ - You may use them to define move constructors and move assignment
+ operators (as described in
+ Copyable and Movable Types).
+
+
+ - You may use them to define
&&
-qualified methods that
+ logically "consume" *this
, leaving it in an unusable
+ or empty state. Note that this applies only to method qualifiers (which come
+ after the closing parenthesis of the function signature); if you want to
+ "consume" an ordinary function parameter, prefer to pass it by value.
+
+ - You may use forwarding references in conjunction with
+ std::forward
,
+ to support perfect forwarding.
+
+ - You may use them to define pairs of overloads, such as one taking
+
Foo&&
and the other taking const Foo&
.
+ Usually the preferred solution is just to pass by value, but an overloaded
+ pair of functions sometimes yields better performance and is sometimes
+ necessary in generic code that needs to support a wide variety of types.
+ As always: if you're writing more complicated code for the sake of
+ performance, make sure you have evidence that it actually helps.
+
Friends
@@ -2373,14 +2324,14 @@ noexcept
- Specifying move constructors as
noexcept
- improves performance in some cases, e.g.
+ improves performance in some cases, e.g.,
std::vector<T>::resize()
moves rather than
copies the objects if T's move constructor is
noexcept
.
- Specifying
noexcept
on a function can
trigger compiler optimizations in environments where
- exceptions are enabled, e.g. compiler does not have to
+ exceptions are enabled, e.g., compiler does not have to
generate extra code for stack-unwinding, if it knows
that no exceptions can be thrown due to a
noexcept
specifier.
@@ -2404,7 +2355,7 @@ noexcept
You may use noexcept
when it is useful for
performance if it accurately reflects the intended semantics
-of your function, i.e. that if an exception is somehow thrown
+of your function, i.e., that if an exception is somehow thrown
from within the function body then it represents a fatal error.
You can assume that noexcept
on move constructors
has a meaningful performance benefit. If you think
@@ -2414,19 +2365,19 @@
noexcept
your project leads.
Prefer unconditional noexcept
if exceptions are
-completely disabled (i.e. most Google C++ environments).
+completely disabled (i.e., most Google C++ environments).
Otherwise, use conditional noexcept
specifiers
with simple conditions, in ways that evaluate false only in
the few cases where the function could potentially throw.
The tests might include type traits check on whether the
-involved operation might throw (e.g.
+involved operation might throw (e.g.,
std::is_nothrow_move_constructible
for
move-constructing objects), or on whether allocation can throw
-(e.g. absl::default_allocator_is_nothrow
for
+(e.g., absl::default_allocator_is_nothrow
for
standard default allocation). Note in many cases the only
possible cause for an exception is allocation failure (we
believe move constructors should not throw except due to
-allocation failure), and there are many applications where it’s
+allocation failure), and there are many applications where it’s
appropriate to treat memory exhaustion as a fatal error rather
than an exceptional condition that your program should attempt
to recover from. Even for other
@@ -2434,7 +2385,7 @@
noexcept
over supporting all possible exception throwing scenarios:
instead of writing a complicated noexcept
clause
that depends on whether a hash function can throw, for example,
-simply document that your component doesn’t support hash
+simply document that your component doesn’t support hash
functions throwing and make it unconditionally
noexcept
.
@@ -2542,9 +2493,9 @@ Casting
like static_cast<float>(double_value)
, or brace
initialization for conversion of arithmetic types like
int64 y = int64{1} << 42
. Do not use
-cast formats like
-int y = (int)x
or int y = int(x)
(but the latter
-is okay when invoking a constructor of a class type).
+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.
C++ introduced a
@@ -2564,12 +2515,13 @@
Casting
The C++-style cast syntax is verbose and cumbersome.
-Do not use C-style casts. Instead, use these C++-style casts when
-explicit type conversion is necessary.
+In general, do not use C-style casts. Instead, use these C++-style
+casts when explicit type conversion is necessary.
+
- Use brace initialization to convert arithmetic types
- (e.g.
int64{x}
). This is the safest approach because code
+ (e.g., int64{x}
). This is the safest approach because code
will not compile if conversion can result in information loss. The
syntax is also concise.
@@ -2694,7 +2646,7 @@ Streams
If you do use streams, avoid the stateful parts of the
streams API (other than error state), such as imbue()
,
xalloc()
, and register_callback()
.
-Use explicit formatting functions (see e.g.
+Use explicit formatting functions (see e.g.,
absl/strings
)
rather than
@@ -2712,9 +2664,8 @@
Streams
Preincrement and Predecrement
-Use prefix form (++i
) of the increment and
-decrement operators with iterators and other template
-objects.
+Use the prefix form (++i
) of the increment
+and decrement operators unless you need postfix semantics.
When a variable
@@ -2725,29 +2676,24 @@
Preincrement and Predecrement
(decrement).
-When the return value is ignored, the "pre" form
-(++i
) is never less efficient than the
-"post" form (i++
), and is often more
-efficient. This is because post-increment (or decrement)
-requires a copy of i
to be made, which is
-the value of the expression. If i
is an
-iterator or other non-scalar type, copying i
-could be expensive. Since the two types of increment
-behave the same when the value is ignored, why not just
-always pre-increment?
+
+A postfix increment/decrement expression evaluates to the value
+as it was before it was modified. This can result in code that is more
+compact but harder to read. The prefix form is generally more readable, is
+never less efficient, and can be more efficient because it doesn't need to
+make a copy of the value as it was before the operation.
+
-The tradition developed, in C, of using post-increment
+
The tradition developed, in C, of using post-increment, even
when the expression value is not used, especially in
for
loops. Some find post-increment easier
to read, since the "subject" (i
) precedes
the "verb" (++
), just like in English.
- For simple scalar
-(non-object) values there is no reason to prefer one form
-and we allow either. For iterators and other template
-types, use pre-increment.
+Use prefix increment/decrement, unless the code explicitly
+needs the result of the postfix increment/decrement expression.
Use of const
@@ -2784,7 +2730,7 @@ Use of const
We strongly recommend using const
-in APIs (i.e. on function parameters, methods, and
+in APIs (i.e., on function parameters, methods, and
non-local variables) wherever it is meaningful and accurate. This
provides consistent, mostly compiler-verified documentation
of what objects an operation can mutate. Having
@@ -2808,7 +2754,7 @@
Use of const
Declare methods to be const
unless they
alter the logical state of the object (or enable the user to modify
- that state, e.g. by returning a non-const reference, but that's
+ that state, e.g., by returning a non-const reference, but that's
rare), or they can't safely be invoked concurrently.
@@ -2847,7 +2793,7 @@ Use of constexpr
Some variables can be declared constexpr
-to indicate the variables are true constants, i.e. fixed at
+to indicate the variables are true constants, i.e., fixed at
compilation/link time. Some functions and constructors
can be declared constexpr
which enables them
to be used in defining a constexpr
@@ -3006,7 +2952,7 @@
64-bit Portability
or std::ostream
.
Unfortunately, the PRI
macros are the only portable way to
- specify a conversion for the standard bitwidth typedefs (e.g.
+ specify a conversion for the standard bitwidth typedefs (e.g.,
int64_t
, uint64_t
, int32_t
,
uint32_t
, etc).
@@ -3126,7 +3072,7 @@
Preprocessor Macros
function/class/variable names.
-Exporting macros from headers (i.e. defining them in a header
+
Exporting macros from headers (i.e., defining them in a header
without #undef
ing 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
@@ -3165,11 +3111,11 @@
sizeof
external or internal data format where a variable of an
appropriate C++ type is not convenient.
-struct data;
+MyStruct data;
memset(&data, 0, sizeof(data));
-memset(&data, 0, sizeof(Struct));
+memset(&data, 0, sizeof(MyStruct));
if (raw_size < sizeof(int)) {
@@ -3227,7 +3173,7 @@ Type deduction
Lambda expression return types can be
deduced in the same way, but this is triggered by omitting the return type,
rather than by an explicit auto
. Confusingly,
- trailing return type syntax for functions
+ trailing return type syntax for functions
also uses auto
in the return-type position, but that doesn't
rely on type deduction; it's just an alternate syntax for an explicit
return type.
@@ -3237,7 +3183,7 @@ Type deduction
one or more of its parameter types. This causes the lambda's call operator
to be a function template instead of an ordinary function, with a separate
template parameter for each auto
function parameter:
- // Sort `vec` in increasing order
+ // Sort `vec` in decreasing order
std::sort(vec.begin(), vec.end(), [](auto lhs, auto rhs) { return lhs > rhs; });
Type deduction
the binding types typically won't be references even if the declaration declares a reference (but they will usually behave like references anyway). +(These summaries omit many details and caveats; see the links for further information.)
@@ -3312,12 +3259,12 @@Type deduction
inconvenience of writing an explicit type. When judging whether the code is clearer, keep in mind that your readers are not necessarily on your team, or familiar with your project, so types that you and - your reviewer experience as as unnecessary clutter will very often + your reviewer experience as unnecessary clutter will very often provide useful information to others. For example, you can assume that the return type ofmake_unique<Foo>()
is obvious,
but the return type of MyWidgetFactory()
probably isn't.
- These principles applies to all forms of type deduction, but the +
These principles apply to all forms of type deduction, but the details vary, as described in the following sections.
Function template argument deduction
@@ -3339,7 +3286,7 @@Local variable type deduction
absl::flat_hash_map<std::string, std::unique_ptr<WidgetWithBellsAndWhistles>>::const_iterator it = my_map_.find(key); -std::array<int, 0> numbers = {4, 8, 15, 16, 23, 42}; +std::array<int, 6> numbers = {4, 8, 15, 16, 23, 42};auto widget_ptr = absl::make_unique<WidgetWithBellsAndWhistles>(arg1, arg2); auto it = my_map_.find(key); @@ -3386,7 +3333,7 @@Parameter type deduction
type will almost always be clearer unless the lambda is explicitly called very close to where it's defined (so that the reader can easily see both), or the lambda is passed to an interface so well-known that it's - obvious what arguments it will eventually be called with (e.g. + obvious what arguments it will eventually be called with (e.g., thestd::sort
example above).Lambda init captures
@@ -3476,6 +3423,52 @@Class template argument deduction
Uses of CTAD must also follow the general rules on Type deduction.
+Designated initializers
+ +Use designated initializers only in their C++20-compliant form.
+ + ++ Designated initializers are a syntax that allows for initializing an + aggregate ("plain old struct") by naming its fields explicitly: +
struct Point { + float x = 0.0; + float y = 0.0; + float z = 0.0; + }; + + Point p = { + .x = 1.0, + .y = 2.0, + // z will be 0.0 + };+ The explicitly listed fields will be initialized as specified, and others + will be initialized in the same way they would be in a traditional aggregate + initialization expression likePoint{1.0, 2.0}
. + + +Designated initializers can make for convenient and highly readable +aggregate expressions, especially for structs with less straightforward +ordering of fields than the
+ + +Point
example above.While designated initializers have long been part of the C standard and +supported by C++ compilers as an extension, only recently have they made it +into the draft C++ standard. They are on track for publishing in C++20.
+ +The rules in the draft C++ standard are stricter than in C and compiler +extensions, requiring that the designated initializers appear in the same order +as the fields appear in the struct definition. So in the example above it is +legal according to draft C++20 to initialize
+ + +x
and then +z
, but noty
and thenx
.Use designated initializers only in the form that is compatible with the +draft C++20 standard: with initializers in the same order as the corresponding +fields appear in the struct definition.
+ + +Lambda expressions
Use lambda expressions where appropriate. Prefer explicit captures @@ -3567,7 +3560,7 @@
Lambda expressions
initializers), but they look nothing like any other variable declaration syntax in C++. In particular, there's no place for the variable's type, or even anauto
placeholder (although init captures can - indicate it indirectly, e.g. with a cast). This can make it difficult to + indicate it indirectly, e.g., with a cast). This can make it difficult to even recognize them as declarations.
std::hash
You can use std::hash
with the types that it supports
"out of the box", but do not specialize it to support additional types.
If you need a hash table with a key type that std::hash
-does not support, consider using legacy hash containers (e.g.
+does not support, consider using legacy hash containers (e.g.,
hash_map
) for now; they use a different default hasher,
which is unaffected by this prohibition.
If you want to use the standard hash containers anyway, you will -need to specify a custom hasher for the key type, e.g.
+need to specify a custom hasher for the key type, e.g.,std::unordered_map<MyKeyType, Value, MyKeyTypeHasher> my_map;
Consult with the type's owners to see if there is an existing hasher @@ -3879,7 +3872,7 @@
Other C++ Features
As with Boost, some modern C++ extensions encourage coding practices that hamper -readability—for example by removing +readability—for example by removing checked redundancy (such as type names) that may be helpful to readers, or by encouraging template metaprogramming. Other extensions duplicate functionality @@ -3917,9 +3910,8 @@
Nonstandard Extensions
Compilers support various extensions that are not part of standard C++. Such
extensions include GCC's __attribute__
, intrinsic functions such
- as __builtin_prefetch
, designated initializers (e.g.
- Foo f = {.field = 3}
), inline assembly, __COUNTER__
,
- __PRETTY_FUNCTION__
, compound statement expressions (e.g.
+ as __builtin_prefetch
, inline assembly, __COUNTER__
,
+ __PRETTY_FUNCTION__
, compound statement expressions (e.g.,
foo = ({ int x; Bar(&x); x })
, variable-length arrays and
alloca()
, and the "Elvis Operator"
a?:b
.
Nonstandard Extensions
- Nonstandard extensions may provide useful features that do not exist - in standard C++. For example, some people think that designated - initializers are more readable than standard C++ features like - constructors. + in standard C++.
Aliases
namespace mynamespace { // Bad: none of these say how they should be used. -using DataPoint = foo::Bar*; -using std::unordered_set; // Bad: just for local convenience -using std::hash; // Bad: just for local convenience +using DataPoint = ::foo::Bar*; +using ::std::unordered_set; // Bad: just for local convenience +using ::std::hash; // Bad: just for local convenience typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator> TimeSeries; } // namespace mynamespace@@ -4034,7 +4024,7 @@
Aliases
classes, explicitly marked internal namespaces, and in .cc files:// In a .cc file -using foo::Bar; +using ::foo::Bar;
Naming
@@ -4112,10 +4102,13 @@General Naming Rules
template parameter.For the purposes of the naming rules below, a "word" is anything that you
-would write in English without internal spaces. This includes abbreviations and
-acronyms; e.g., for "camel
-case" or "Pascal case," in which the first letter of each word is
-capitalized, use a name like StartRpc()
, not
+would write in English without internal spaces. This includes abbreviations,
+such as acronyms and initialisms. For names written in mixed case (also
+sometimes referred to as
+"camel case" or
+"Pascal case"), in
+which the first letter of each word is capitalized, prefer to capitalize
+abbreviations as single words, e.g., StartRpc()
rather than
StartRPC()
.
Template parameters should follow the naming style for their @@ -4163,8 +4156,8 @@
Type Names
letter for each new word, with no underscores:MyExcitingClass
, MyExcitingEnum
.
-The names of all types — classes, structs, type aliases, -enums, and type template parameters — have the same naming convention. +
The names of all types — classes, structs, type aliases, +enums, and type template parameters — have the same naming convention. Type names should start with a capital letter and have a capital letter for each new word. No underscores. For example:
@@ -4180,7 +4173,7 @@Type Names
using PropertiesMap = hash_map<UrlTableProperties *, std::string>; // enums -enum UrlTableErrors { ... +enum class UrlTableError { ...Variable Names
@@ -4244,10 +4237,10 @@Constant Names
const int kAndroid8_0_0 = 24; // Android 8.0.0 -All such variables with static storage duration (i.e. statics and globals, +
All such variables with static storage duration (i.e., statics and globals, see Storage Duration for details) should be named this way. This -convention is optional for variables of other storage classes, e.g. automatic +convention is optional for variables of other storage classes, e.g., automatic variables, otherwise the usual variable naming rules apply.
Function Names
@@ -4312,25 +4305,20 @@Namespace Names
Enumerator Names
-Enumerators (for both scoped and unscoped enums) should be named either like
-constants or like
-macros: either kEnumName
or
+
Enumerators (for both scoped and unscoped enums) should be named like
+constants, not like
+macros. That is, use kEnumName
not
ENUM_NAME
.
Preferably, the individual enumerators should be named
-like constants. However, it
-is also acceptable to name them like
-macros. The enumeration name,
-UrlTableErrors
(and
-AlternateUrlTableErrors
), is a type, and
-therefore mixed case.
enum UrlTableErrors { + +enum class UrlTableError { kOk = 0, - kErrorOutOfMemory, - kErrorMalformedInput, + kOutOfMemory, + kMalformedInput, }; -enum AlternateUrlTableErrors { ++enum class AlternateUrlTableError { OK = 0, OUT_OF_MEMORY = 1, MALFORMED_INPUT = 2, @@ -4341,10 +4329,8 @@Enumerator Names
like macros. This caused problems with name collisions between enum values and macros. Hence, the change to prefer constant-style naming -was put in place. New code should prefer constant-style -naming if possible. However, there is no reason to change -old code to use constant-style names, unless the old -names are actually causing a compile-time problem. +was put in place. New code should use constant-style +naming. @@ -4398,7 +4384,7 @@Comments
When writing your comments, write for your audience: the next contributor who will need to -understand your code. Be generous — the next +understand your code. Be generous — the next one may be you!
Comment Style
@@ -4452,8 +4438,9 @@File Contents
Class Comments
-Every non-obvious class declaration should have an accompanying -comment that describes what it is for and how it should be used.
+Every non-obvious class or struct declaration should have an +accompanying comment that describes what it is for and how it should +be used.
// Iterates over the contents of a GargantuanTable. // Example: @@ -4477,7 +4464,7 @@Class Comments
The class comment is often a good place for a small example code snippet demonstrating a simple and focused usage of the class.
-When sufficiently separated (e.g.
.h
and.cc
+When sufficiently separated (e.g.,
@@ -4493,7 +4480,7 @@.h
and.cc
files), comments describing the use of the class should go together with its interface definition; comments about the class operation and implementation should accompany the implementation of the class's methods.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 +obvious (e.g., simple accessors for obvious properties of the class). These comments should open with descriptive verbs in the indicative mood ("Opens the file") rather than verbs in the imperative ("Open the file"). The comment describes the function; it does not @@ -4653,7 +4640,7 @@
Line-end Comments
error has already been logged when the function returns. -Function Argument Comments
+Function Argument Comments
When the meaning of a function argument is nonobvious, consider one of the following remedies:
@@ -4777,7 +4764,7 @@TODO Comments
@@ -4846,7 +4833,7 @@// TODO(kl@gmail.com): Use a "*" here for concatenation operator. // TODO(Zeke) change this to use relations. -// TODO(bug 12345): remove the "Last visitors" feature +// TODO(bug 12345): remove the "Last visitors" feature.Line Length
- a comment line which is not feasible to split without harming - readability, ease of cut and paste or auto-linking -- e.g. if a line + readability, ease of cut and paste or auto-linking -- e.g., if a line contains an example command or a literal URL longer than 80 characters.
- a raw-string literal with content that exceeds 80 characters. Except for
@@ -4878,7 +4865,7 @@
Non-ASCII Characters
ASCII.Hex encoding is also OK, and encouraged where it -enhances readability — for example, +enhances readability — for example,
"\xEF\xBB\xBF"
, or, even more simply,u8"\uFEFF"
, is the Unicode zero-width no-break space character, which would be invisible if @@ -5138,7 +5125,7 @@Braced Initializer List Format
Format a braced initializer list exactly like you would format a function call in its place.
-If the braced list follows a name (e.g. a type or +
If the braced list follows a name (e.g., a type or variable name), format as if the
@@ -5172,19 +5159,10 @@{}
were the parentheses of a function call with that name. If there is no name, assume a zero-length name.Braced Initializer List Format
Conditionals
-Prefer no spaces inside parentheses. The
- -if
-andelse
keywords belong on separate lines.There are two acceptable formats for a basic -conditional statement. One includes spaces between the -parentheses and the condition, and one does not.
- -The most common form is without spaces. Either is -fine, but be consistent. If you are modifying a -file, use the format that is already present. If you are -writing new code, use the format that the other files in -that directory or project use. If in doubt and you have -no personal preference, do not add the spaces.
+The
if
andelse
keywords belong on separate lines. + There should be a space between theif
and the open parenthesis, + and between the close parenthesis and the curly brace (if any), but no space + between the parentheses and the condition.if (condition) { // no spaces inside parentheses ... // 2 space indent. @@ -5195,22 +5173,8 @@
-Conditionals
}If you prefer you may add spaces inside the -parentheses:
- -if ( condition ) { // spaces inside parentheses - rare - ... // 2 space indent. -} else { // The else goes on the same line as the closing brace. - ... -} -
- -Note that in all cases you must have a space between -the
-if
and the open parenthesis. You must -also have a space between the close parenthesis and the -curly brace, if you're using one.if(condition) { // Bad - space missing after IF. +if ( condition ) { // Bad - space between the parentheses and the condition if (condition){ // Bad - space missing before {. if(condition){ // Doubly bad.
@@ -5446,8 +5410,8 @@Boolean Expressions
line is also allowed. Feel free to insert extra parentheses judiciously because they can be very helpful in increasing readability when used -appropriately. Also note that you should always use -the punctuation operators, such as +appropriately, but be careful about overuse. Also note that you +should always use the punctuation operators, such as&&
and~
, rather than the word operators, such asand
andcompl
. @@ -5658,13 +5622,6 @@Namespace Formatting
} // namespace -When declaring nested namespaces, put each namespace -on its own line.
- -namespace foo { -namespace bar { -
-Horizontal Whitespace
Use of horizontal whitespace depends on location. Never put @@ -5784,10 +5741,17 @@
Vertical Whitespace
well help readability. - A blank line before a comment line usually helps - readability — the introduction of a new comment suggests + readability — the introduction of a new comment suggests the start of a new thought, and the blank line makes it clear that the comment goes with the following thing instead of the preceding. + +
- Blank lines immediately inside a declaration of a namespace or block of + namespaces may help readability by visually separating the load-bearing + content from the (largely non-semantic) organizational wrapper. Especially + when the first declaration inside the namespace(s) is preceded by a comment, + this becomes a special case of the previous rule, helping the comment to + "attach" to the subsequent declaration.