Movatterモバイル変換


[0]ホーム

URL:


Google C++ Style Guide

Background

C++ is one of the main development languages used bymany of Google's open-source projects. As every C++programmer knows, the language has many powerful features, butthis power brings with it complexity, which in turn can makecode more bug-prone and harder to read and maintain.

The goal of this guide is to manage this complexity bydescribing in detail the dos and don'ts of writing C++code. These rules exist tokeep the code base manageable while still allowingcoders to use C++ language features productively.

Style, also known as readability, is what we callthe conventions that govern our C++ code. The term Style is abit of a misnomer, since these conventions cover far more thanjust source file formatting.

Most open-source projects developed byGoogle conform to the requirements in this guide.

Note that this guide is not a C++ tutorial: we assume thatthe reader is familiar with the language.

Goals of the Style Guide

Why do we have this document?

There are a few core goals that we believe this guide shouldserve. These are the fundamentalwhys thatunderlie all of the individual rules. By bringing these ideas tothe fore, we hope to ground discussions and make it clearer to ourbroader community why the rules are in place and why particulardecisions have been made. If you understand what goals each rule isserving, it should be clearer to everyone when a rule may be waived(some can be), and what sort of argument or alternative would benecessary to change a rule in the guide.

The goals of the style guide as we currently see them are as follows:

Style rules should pull their weight
The benefit of a style rulemust be large enough to justify asking all of our engineers toremember it. The benefit is measured relative to the codebase we wouldget without the rule, so a rule against a very harmful practice maystill have a small benefit if people are unlikely to do itanyway. This principle mostly explains the rules we don’t have, ratherthan the rules we do: for example,goto contravenes manyof the following principles, but is already vanishingly rare, so the StyleGuide doesn’t discuss it.
Optimize for the reader, not the writer
Our codebase (and most individual components submitted to it) isexpected to continue for quite some time. As a result, more time willbe spent reading most of our code than writing it. We explicitlychoose to optimize for the experience of our average software engineerreading, maintaining, and debugging code in our codebase rather thanease when writing said code. "Leave a trace for the reader" is aparticularly common sub-point of this principle: When somethingsurprising or unusual is happening in a snippet of code (for example,transfer of pointer ownership), leaving textual hints for the readerat the point of use is valuable (std::unique_ptrdemonstrates the ownership transfer unambiguously at the callsite).
Be consistent with existing code
Using one style consistently through our codebase lets us focus onother (more important) issues. Consistency also allows for automation:tools that format your code or adjust your#includes onlywork properly when your code is consistent with the expectations ofthe tooling. In many cases, rules that are attributed to "BeConsistent" boil down to "Just pick one and stop worrying about it";the potential value of allowing flexibility on these points isoutweighed by the cost of having people argue over them. However,there are limits to consistency; it is a good tie breaker when thereis no clear technical argument, nor a long-term direction. It appliesmore heavily locally (per file, or for a tightly-related set ofinterfaces). Consistency should not generally be used as ajustification to do things in an old style without considering thebenefits of the new style, or the tendency of the codebase to convergeon newer styles over time.
Be consistent with the broader C++ community when appropriate
Consistency with the way other organizations use C++ has value forthe same reasons as consistency within our code base. If a feature inthe C++ standard solves a problem, or if some idiom is widely knownand accepted, that's an argument for using it. However, sometimesstandard features and idioms are flawed, or were just designed withoutour codebase's needs in mind. In those cases (as described below) it'sappropriate to constrain or ban standard features. In some cases weprefer a homegrown or third-party library over a library defined inthe C++ Standard, either out of perceived superiority or insufficientvalue to transition the codebase to the standard interface.
Avoid surprising or dangerous constructs
C++ has features that are more surprising or dangerous than onemight think at a glance. Some style guide restrictions are in place toprevent falling into these pitfalls. There is a high bar for styleguide waivers on such restrictions, because waiving such rules oftendirectly risks compromising program correctness.
Avoid constructs that our average C++ programmer would find trickyor hard to maintain
C++ has features that may not be generally appropriate because ofthe complexity they introduce to the code. In widely usedcode, it may be more acceptable to usetrickier language constructs, because any benefits of more compleximplementation are multiplied widely by usage, and the cost in understandingthe complexity does not need to be paid again when working with newportions of the codebase. When in doubt, waivers to rules of this typecan be sought by askingyour project leads. This is specificallyimportant for our codebase because code ownership and team membershipchanges over time: even if everyone that works with some piece of codecurrently understands it, such understanding is not guaranteed to hold afew years from now.
Be mindful of our scale
With a codebase of 100+ million lines and thousands of engineers,some mistakes and simplifications for one engineer can become costlyfor many. For instance it's particularly important toavoid polluting the global namespace: name collisions across acodebase of hundreds of millions of lines are difficult to work withand hard to avoid if everyone puts things into the globalnamespace.
Concede to optimization when necessary
Performance optimizations can sometimes be necessary andappropriate, even when they conflict with the other principles of thisdocument.

The intent of this document is to provide maximal guidance withreasonable restriction. As always, common sense and good taste shouldprevail. By this we specifically refer to the established conventionsof the entire Google C++ community, not just your personal preferencesor those of your team. Be skeptical about and reluctant to useclever or unusual constructs: the absence of a prohibition is not thesame as a license to proceed. Use your judgment, and if you areunsure, please don't hesitate to ask your project leads to get additionalinput.

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.

Do not usenon-standard extensions.

Consider portability to other environments before using featuresfrom C++17 and C++20 in your project.

Header Files

In general, every.cc file should have anassociated.h file. There are some commonexceptions, such as unit tests and small.cc files containingjust amain() function.

Correct use of header files can make a huge difference tothe readability, size and performance of your code.

The following rules will guide you through the variouspitfalls of using header files.

Self-contained Headers

Header files should be self-contained (compile on their own) andend in.h. Non-header files that are meant for inclusionshould end in.inc and be used sparingly.

All header files should be self-contained. Users and refactoringtools should not have to adhere to special conditions to include theheader. Specifically, a header shouldhaveheader guards and include allother headers it needs.

When a header declares inline functions or templates that clients of theheader will instantiate, the inline functions and templates must also havedefinitions in the header, either directly or in files it includes. Do not movethese definitions to separately included header (-inl.h) files;this practice was common in the past, but is no longer allowed. When allinstantiations of a template occur in one.cc file, either becausethey'reexplicit or because the definition is accessible to onlythe.cc file, the template definition can be kept in that file.

There are rare cases where a file designed to be included is notself-contained. These are typically intended to be included at unusuallocations, such as the middle of another file. They might notuseheader guards, and might not includetheir prerequisites. Name such files with the.incextension. Use sparingly, and prefer self-contained headers whenpossible.

The #define Guard

All header files should have#define guards toprevent multiple inclusion. The format of the symbol nameshould be<PROJECT>_<PATH>_<FILE>_H_.

To guarantee uniqueness, they shouldbe based on the full path in a project's source tree. Forexample, the filefoo/src/bar/baz.h inprojectfoo should have the followingguard:

#ifndef FOO_BAR_BAZ_H_#define FOO_BAR_BAZ_H_...#endif  // FOO_BAR_BAZ_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 intendsto provide a declaration or definition of that symbol. It should notinclude header files for any other reason.

Do not rely on transitive inclusions. This allows people to removeno-longer-needed#include statements from their headers withoutbreaking clients. This also applies to related headers-foo.cc should includebar.h if it uses asymbol from it even iffoo.hincludesbar.h.

Forward Declarations

Avoid using forward declarations where possible. Instead,include the headers you need.

A "forward declaration" is a declaration of an entity without an associated definition.

// In a C++ source file:class B;void FuncInB();extern int variable_in_b;ABSL_DECLARE_FLAG(flag_in_b);

Try to avoid forward declarations of entitiesdefined in another project.

Defining Functions in Header Files

Include the definition of a function at its point of declaration in a header file onlywhen the definition is short. If the definition otherwise has a reason be in the header,put it in an internal part of the file. If necessary to make the definition ODR-safe, markit with aninline specifier.

Functions defined in header files are sometimes referred to as "inline functions",which is a somewhat overloaded term that refers to several distinct but overlappingsituations:

  1. Atextually inline symbol's definition is exposed to the reader at the point of declaration.
  2. A function or variable defined in a header file isexpandable inline since its definition is available forinline expansion by the compiler, which can lead to more efficient object code.
  3. ODR-safe entities do not violate the"One Definition Rule", which often requires theinline keyword for things defined in header files .

While functions tend to be a more common source of confusion, these definitions apply tovariables as well, and so do the rules here.

Only define a function at its public declaration if it is short, say, 10 lines or fewer. Putlonger function bodies in the.cc file unless they must be in the header forperformance or technical reasons.

Even if a definition must be in the header, this is not a sufficient reason to put it withinthe public part. Instead, the definition can be in an internal part of the header, such as theprivate section of a class, within a namespace that includes the wordinternal, or below a comment like// Implementation details onlybelow here.

Once a definition is in a header file, it must be ODR-safe by having theinlinespecifier or being implicitly specified inline by being a function template or defined in a classbody when first declared.

template <typename T>class Foo { public:  int bar() { return bar_; }  void MethodWithHugeBody(); private:  int bar_;};// Implementation details only below heretemplate <typename T>void Foo<T>::MethodWithHugeBody() {  ...}

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'sheaders.

All of a project's header files should belisted as descendants of the project's sourcedirectory without use of UNIX directory aliases. (the current directory) or..(the parent directory). For example,google-awesome-project/src/base/logging.hshould be included as:

#include "base/logging.h"

Headers should only be included using an angle-bracketed path if the libraryrequires you to do so. In particular, the following headers require anglebrackets:

Indir/foo.cc ordir/foo_test.cc, whose mainpurpose is to implement or test the stuff indir2/foo2.h, order your includesas follows:

  1. dir2/foo2.h.
  2. A blank line
  3. C system headers, and any other headers in angle brackets with the.h extension, e.g.,<unistd.h>,<stdlib.h>,<Python.h>.
  4. A blank line
  5. C++ standard library headers (without file extension), e.g.,<algorithm>,<cstddef>.
  6. A blank line
  7. Other libraries'.h files.
  8. A blank line
  9. Your project's.h files.

Separate each non-empty group with one blank line.

With the preferred ordering, if the related headerdir2/foo2.h omits any necessaryincludes, the build ofdir/foo.ccordir/foo_test.cc will break.Thus, this rule ensures that build breaks show up firstfor the people working on these files, not for innocentpeople in other packages.

dir/foo.cc anddir2/foo2.h are usually in the samedirectory (e.g.,base/basictypes_test.cc andbase/basictypes.h), but may sometimes be in differentdirectories too.

Note that the C headers such asstddef.hare essentially interchangeable with their C++ counterparts(cstddef).Either style is acceptable, but prefer consistency with existing code.

Within each section the includes should be orderedalphabetically. Note that older code might not conform tothis rule and should be fixed when convenient.

For example, the includes ingoogle-awesome-project/src/foo/internal/fooserver.ccmight look like this:

#include "foo/server/fooserver.h"#include <sys/types.h>#include <unistd.h>#include <string>#include <vector>#include "base/basictypes.h"#include "foo/server/bar.h"#include "third_party/absl/flags/flag.h"

Exception:

Sometimes, system-specific code needsconditional includes. Such code can put conditionalincludes after other includes. Of course, keep yoursystem-specific code small and localized. Example:

#include "foo/public/fooserver.h"#include "base/port.h"  // For LANG_CXX11.#ifdef LANG_CXX11#include <initializer_list>#endif  // LANG_CXX11

Scoping

Namespaces

With few exceptions, place code in a namespace. Namespacesshould have unique names based on the project name, and possiblyits path. Do not useusing-directives (e.g.,using namespace foo). Do not useinline namespaces. For unnamed namespaces, seeInternal Linkage.

Namespaces subdivide the global scopeinto distinct, named scopes, and so are useful for preventingname collisions in the global scope.

Namespaces provide a method for preventing name conflictsin large programs while allowing most code to use reasonablyshort names.

For example, if two different projects have a classFoo in the global scope, these symbols maycollide at compile time or at runtime. If each projectplaces their code in a namespace,project1::Fooandproject2::Foo are now distinct symbols thatdo not collide, and code within each project's namespacecan continue to refer toFoo without the prefix.

Inline namespaces automatically place their names inthe enclosing scope. Consider the following snippet, forexample:

namespace outer {inline namespace inner {  void foo();}  // namespace inner}  // namespace outer

The expressionsouter::inner::foo() andouter::foo() are interchangeable. Inlinenamespaces are primarily intended for ABI compatibilityacross versions.

Namespaces can be confusing, because they complicatethe mechanics of figuring out what definition a name refersto.

Inline namespaces, in particular, can be confusingbecause names aren't actually restricted to the namespacewhere they are declared. They are only useful as part ofsome larger versioning policy.

In some contexts, it's necessary to repeatedly refer tosymbols by their fully-qualified names. For deeply-nestednamespaces, this can add a lot of clutter.

Namespaces should be used as follows:

Internal Linkage

When definitions in a.cc file do not need to bereferenced outside that file, give them internal linkage by placingthem in an unnamed namespace or declaring themstatic.Do not use either of these constructs in.h files.

All declarations can be given internal linkage by placing them in unnamednamespaces. Functions and variables can also be given internal linkage bydeclaring themstatic. This means that anything you're declaringcan't be accessed from another file. If a different file declares something withthe same name, then the two entities are completely independent.

Use of internal linkage in.cc files is encouragedfor all code that does not need to be referenced elsewhere.Do not use internal linkage in.h files.

Format unnamed namespaces like named namespaces. In the terminating comment, leave the namespace name empty:

namespace {...}  // namespace

Nonmember, Static Member, and Global Functions

Prefer placing nonmember functions in a namespace; use completely globalfunctions rarely. Do not use a class simply to group static members. Staticmethods of a class should generally be closely related to instances of theclass or the class's static data.

Nonmember and static member functions can be useful insome situations. Putting nonmember functions in anamespace avoids polluting the global namespace.

Nonmember and static member functions may make more senseas members of a new class, especially if they accessexternal resources or have significant dependencies.

Sometimes it is useful to define afunction not bound to a class instance. Such a functioncan be either a static member or a nonmember function.Nonmember functions should not depend on externalvariables, and should nearly always exist in a namespace.Do not create classes only to group static members;this is no different than just giving the names acommon prefix, and such grouping is usually unnecessary anyway.

If you define a nonmember function and it is onlyneeded in its.cc file, useinternal linkage to limitits scope.

Local Variables

Place a function's variables in the narrowest scopepossible, and initialize variables in the declaration.

C++ allows you to declare variables anywhere in a function.We encourage you to declare them in a scope as local aspossible, and as close to the first use as possible.This makes it easier for the reader to find thedeclaration and see what type the variable is and what itwas initialized to. In particular, initialization shouldbe used instead of declaration and assignment, e.g.,:

int i;i = f();      // Bad -- initialization separate from declaration.
int i = f();  // Good -- declaration has initialization.
int jobs = NumJobs();// More code...f(jobs);      // Bad -- declaration separate from use.
int jobs = NumJobs();f(jobs);      // Good -- declaration immediately (or closely) followed by use.
std::vector<int> v;v.push_back(1);  // Prefer initializing using brace initialization.v.push_back(2);
std::vector<int> v = {1, 2};  // Good -- v starts initialized.

Variables needed forif,whileandfor statements should normally be declaredwithin those statements, so that such variables are confinedto those scopes. E.g.:

while (const char* p = strchr(str, '/')) str = p + 1;

There is one caveat: if the variable is an object, itsconstructor is invoked every time it enters scope and iscreated, and its destructor is invoked every time it goesout of scope.

// Inefficient implementation:for (int i = 0; i < 1000000; ++i) {  Foo f;  // My ctor and dtor get called 1000000 times each.  f.DoSomething(i);}

It may be more efficient to declare such a variableused in a loop outside that loop:

Foo f;  // My ctor and dtor get called once each.for (int i = 0; i < 1000000; ++i) {  f.DoSomething(i);}

Static and Global Variables

Objects withstatic storage duration are forbidden unless they aretriviallydestructible. Informally this means that the destructor does not doanything, even taking member and base destructors into account. More formally itmeans that the type has no user-defined or virtual destructor and that all basesand 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 atnamespace scope is discouraged, but allowed in limited circumstances; see belowfor details.

As a rule of thumb: a global variable satisfies these requirements if itsdeclaration, considered in isolation, could beconstexpr.

Every object has astorage duration, which correlates with itslifetime. Objects with static storage duration live from the point of theirinitialization until the end of the program. Such objects appear as variables atnamespace scope ("global variables"), as static data members of classes, or asfunction-local variables that are declared with thestaticspecifier. Function-local static variables are initialized when control firstpasses through their declaration; all other objects with static storage durationare initialized as part of program start-up. All objects with static storageduration are destroyed at program exit (which happens before unjoined threadsare terminated).

Initialization may bedynamic, which means that somethingnon-trivial happens during initialization. (For example, consider a constructorthat allocates memory, or a variable that is initialized with the currentprocess ID.) The other kind of initialization isstaticinitialization. The two aren't quite opposites, though: staticinitializationalways happens to objects with static storage duration(initializing the object either to a given constant or to a representationconsisting of all bytes set to zero), whereas dynamic initialization happensafter that, if required.

Global and static variables are very useful for a large number ofapplications: named constants, auxiliary data structures internal to sometranslation unit, command-line flags, logging, registration mechanisms,background infrastructure, etc.

Global and static variables that use dynamic initialization or havenon-trivial destructors create complexity that can easily lead to hard-to-findbugs. Dynamic initialization is not ordered across translation units, andneither is destruction (except that destructionhappens in reverse order of initialization). When one initialization refers toanother variable with static storage duration, it is possible that this causesan object to be accessed before its lifetime has begun (or after its lifetimehas ended). Moreover, when a program starts threads that are not joined at exit,those threads may attempt to access objects after their lifetime has ended iftheir destructor has already run.

Decision on destruction

When destructors are trivial, their execution is not subject to ordering atall (they are effectively not "run"); otherwise we are exposed to the risk ofaccessing objects after the end of their lifetime. Therefore, we only allowobjects with static storage duration if they are trivially destructible.Fundamental types (like pointers andint) are triviallydestructible, as are arrays of trivially destructible types. Note thatvariables marked withconstexpr are trivially destructible.

const int kNum = 10;  // Allowedstruct X { int n; };const X kX[] = {{1}, {2}, {3}};  // Allowedvoid foo() {  static const char* const kMessages[] = {"hello", "world"};  // Allowed}// Allowed: constexpr guarantees trivial destructor.constexpr std::array<int, 3> kArray = {1, 2, 3};
// bad: non-trivial destructorconst std::string kFoo = "foo";// Bad for the same reason, even though kBar is a reference (the// rule also applies to lifetime-extended temporary objects).const std::string& kBar = StrCat("a", "b", "c");void bar() {  // Bad: non-trivial destructor.  static std::map<int, int> kData = {{1, 0}, {2, 0}, {3, 0}};}

Note that references are not objects, and thus they are not subject to theconstraints on destructibility. The constraint on dynamic initialization stillapplies, though. In particular, a function-local static reference of the formstatic T& t = *new T; is allowed.

Decision on initialization

Initialization is a more complex topic. This is because we must not onlyconsider whether class constructors execute, but we must also consider theevaluation of the initializer:

int n = 5;    // Fineint m = f();  // ? (Depends on f)Foo x;        // ? (Depends on Foo::Foo)Bar y = g();  // ? (Depends on g and on Bar::Bar)

All but the first statement expose us to indeterminate initializationordering.

The concept we are looking for is calledconstant initialization inthe formal language of the C++ standard. It means that the initializingexpression is a constant expression, and if the object is initialized by aconstructor call, then the constructor must be specified asconstexpr, too:

struct Foo { constexpr Foo(int) {} };int n = 5;  // Fine, 5 is a constant expression.Foo x(2);   // Fine, 2 is a constant expression and the chosen constructor is constexpr.Foo a[] = { Foo(1), Foo(2), Foo(3) };  // Fine

Constant initialization is always allowed. Constant initialization ofstatic storage duration variables should be marked withconstexprorconstinit.Any non-local static storageduration variable that is not so marked should be presumed to havedynamic initialization, and reviewed very carefully.

By contrast, the following initializations are problematic:

// Some declarations used below.time_t time(time_t*);      // Not constexpr!int f();                   // Not constexpr!struct Bar { Bar() {} };// Problematic initializations.time_t m = time(nullptr);  // Initializing expression not a constant expression.Foo y(f());                // DittoBar b;                     // Chosen constructor Bar::Bar() not constexpr.

Dynamic initialization of nonlocal variables is discouraged, and in generalit is forbidden. However, we do permit it if no aspect of the program dependson the sequencing of this initialization with respect to all otherinitializations. Under those restrictions, the ordering of the initializationdoes not make an observable difference. For example:

int p = getpid();  // Allowed, as long as no other static variable                   // uses p in its own initialization.

Dynamic initialization of static local variables is allowed (and common).

Common patterns

thread_local Variables

thread_local variables that aren't declared inside a functionmust be initialized with a true compile-time constant,and this must be enforced by using theconstinitattribute. Preferthread_local over other ways of defining thread-local data.

Variables can be declared with thethread_local specifier:

thread_local Foo foo = ...;

Such a variable is actually a collection of objects, so that when differentthreads access it, they are actually accessing different objects.thread_local variables are much likestatic storage duration variablesin many respects. For instance, they can be declared at namespace scope,inside functions, or as static class members, but not as ordinary classmembers.

thread_local variable instances are initialized much likestatic variables, except that they must be initialized separately for eachthread, rather than once at program startup. This means thatthread_local variables declared within a function are safe, butotherthread_local variables are subject to the sameinitialization-order issues as static variables (and more besides).

thread_local variables have a subtle destruction-order issue:during thread shutdown,thread_local variables will be destroyedin the opposite order of their initialization (as is generally true in C++).If code triggered by the destructor of anythread_local variablerefers to any already-destroyedthread_local on that thread, we willget a particularly hard to diagnose use-after-free.

thread_local variables at class or namespace scope must be 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 withconstinit (orconstexpr, but that should be rare):

   constinit thread_local Foo foo = ...;

thread_local variables inside a function have no initialization concerns, but still risk use-after-free during thread exit. Note that you can use a function-scopethread_local to simulate a class- or namespace-scopethread_local by defining a function or static method that exposes it:

Foo& MyThreadLocalFoo() {  thread_local Foo result = ComplicatedInitialization();  return result;}

Note thatthread_local variables will be destroyed whenever a thread exits. If the destructor of any such variable refers to any other (potentially-destroyed)thread_local we will suffer from hard to diagnose use-after-free bugs. Prefer trivial types, or types that provably run no user-provided code at destruction to minimize the potential of accessing any otherthread_local.

thread_local should be preferred over other mechanisms fordefining thread-local data.

Classes

Classes are the fundamental unit of code in C++. Naturally,we use them extensively. This section lists the main dos anddon'ts you should follow when writing a class.

Doing Work in Constructors

Avoid virtual method calls in constructors, and avoidinitialization that can fail if you can't signal an error.

It is possible to perform arbitrary initialization in the bodyof the constructor.

Constructors should never call virtual functions. If appropriatefor your code ,terminating the program may be an appropriate error handlingresponse. Otherwise, consider a factory functionorInit() method as described inTotW #42.AvoidInit() methods on objects withno other states that affect which public methods may be called(semi-constructed objects of this form are particularly hard to workwith correctly).

Implicit Conversions

Do not define implicit conversions. Use theexplicitkeyword for conversion operators and single-argumentconstructors.

Implicit conversions allow anobject of one type (called thesource type) tobe used where a different type (called thedestinationtype) is expected, such as when passing anint argument to a function that takes adouble parameter.

In addition to the implicit conversions defined by the language,users can define their own, by adding appropriate members to theclass definition of the source or destination type. An implicitconversion in the source type is defined by a type conversion operatornamed after the destination type (e.g.,operatorbool()). An implicit conversion in the destinationtype is defined by a constructor that can take the source type asits only argument (or only argument with no default value).

Theexplicit keyword can be applied to a constructoror a conversion operator, to ensure that it can only beused when the destination type is explicit at the point of use,e.g., with a cast. This applies not only to implicit conversions, but tolist initialization syntax:

class Foo {  explicit Foo(int x, double y);  ...};void Func(Foo f);
Func({42, 3.14});  // Error

This kind of code isn't technically an implicit conversion, but thelanguage treats it as one as far asexplicit is concerned.

Type conversion operators, and constructors that arecallable with a single argument, must be markedexplicit in the class definition. As anexception, copy and move constructors should not beexplicit, since they do not perform typeconversion.

Implicit conversions can sometimes be necessary and appropriate fortypes that are designed to be interchangeable, for example when objectsof two types are just different representations of the same underlyingvalue. In that case, contactyour project leads to request a waiverof this rule.

Constructors that cannot be called with a single argumentmay omitexplicit. Constructors thattake a singlestd::initializer_list parameter shouldalso omitexplicit, 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/ormoving if these operations are clear and meaningful for your type.

A movable type is one that can be initialized and assignedfrom temporaries.

A copyable type is one that can be initialized or assigned fromany other object of the same type (so is also movable by definition), with thestipulation that the value of the source does not change.std::unique_ptr<int> is an example of a movable but notcopyable type (since the value of the sourcestd::unique_ptr<int> must be modified during assignment tothe destination).int andstd::string are examples ofmovable types that are also copyable. (Forint, the move and copyoperations are the same; forstd::string, there exists a move operationthat is less expensive than a copy.)

For user-defined types, the copy behavior is defined by the copyconstructor and the copy-assignment operator. Move behavior is defined by themove constructor and the move-assignment operator, if they exist, or by thecopy constructor and the copy-assignment operator otherwise.

The copy/move constructors can be implicitly invoked by the compilerin some situations, e.g., when passing objects by value.

Objects of copyable and movable types can be passed and returned by value,which makes APIs simpler, safer, and more general. Unlike when passing objectsby pointer or reference, there's no risk of confusion over ownership,lifetime, mutability, and similar issues, and no need to specify them in thecontract. It also prevents non-local interactions between the client and theimplementation, which makes them easier to understand, maintain, and optimize bythe compiler. Further, such objects can be used with generic APIs thatrequire pass-by-value, such as most containers, and they allow for additionalflexibility in e.g., type composition.

Copy/move constructors and assignment operators are usuallyeasier to define correctly than alternativeslikeClone(),CopyFrom() orSwap(),because they can be generated by the compiler, either implicitly orwith= default. They are concise, and ensurethat all data members are copied. Copy and moveconstructors are also generally more efficient, because they don'trequire heap allocation or separate initialization and assignmentsteps, and they're eligible for optimizations such ascopy elision.

Move operations allow the implicit and efficient transfer ofresources out of rvalue objects. This allows a plainer coding stylein some cases.

Some types do not need to be copyable, and providing copyoperations for such types can be confusing, nonsensical, or outrightincorrect. Types representing singleton objects (Registerer),objects tied to a specific scope (Cleanup), or closely coupled toobject identity (Mutex) cannot be copied meaningfully.Copy operations for base class types that are to be usedpolymorphically are hazardous, because use of them can lead toobject slicing.Defaulted or carelessly-implemented copy operations can be incorrect, and theresulting bugs can be confusing and difficult to diagnose.

Copy constructors are invoked implicitly, which makes theinvocation easy to miss. This may cause confusion for programmers used tolanguages where pass-by-reference is conventional or mandatory. It may alsoencourage excessive copying, which can cause performance problems.

Every class's public interface must make clear which copy and moveoperations the class supports. This should usually take the form of explicitlydeclaring and/or deleting the appropriate operations in thepublicsection of the declaration.

Specifically, a copyable class should explicitly declare the copyoperations, a move-only class should explicitly declare the move operations, anda non-copyable/movable class should explicitly delete the copy operations. Acopyable class may also declare move operations in order to support efficientmoves. Explicitly declaring or deleting all four copy/move operations ispermitted, but not required. If you provide a copy or move assignment operator,you must also provide the corresponding constructor.

class Copyable { public:  Copyable(const Copyable& other) = default;  Copyable& operator=(const Copyable& other) = default;  // The implicit move operations are suppressed by the declarations above.  // You may explicitly declare move operations to support efficient moves.};class MoveOnly { public:  MoveOnly(MoveOnly&& other) = default;  MoveOnly& operator=(MoveOnly&& other) = default;  // The copy operations are implicitly deleted, but you can  // spell that out explicitly if you want:  MoveOnly(const MoveOnly&) = delete;  MoveOnly& operator=(const MoveOnly&) = delete;};class NotCopyableOrMovable { public:  // Not copyable or movable  NotCopyableOrMovable(const NotCopyableOrMovable&) = delete;  NotCopyableOrMovable& operator=(const NotCopyableOrMovable&)      = delete;  // The move operations are implicitly disabled, but you can  // spell that out explicitly if you want:  NotCopyableOrMovable(NotCopyableOrMovable&&) = delete;  NotCopyableOrMovable& operator=(NotCopyableOrMovable&&)      = delete;};

These declarations/deletions can be omitted only if they are obvious:

A type should not be copyable/movable if the meaning ofcopying/moving is unclear to a casual user, or if it incurs unexpectedcosts. Move operations for copyable types are strictly a performanceoptimization and are a potential source of bugs and complexity, soavoid defining them unless they are significantly more efficient thanthe corresponding copy operations. If your type provides copy operations, it isrecommended that you design your class so that the default implementation ofthose operations is correct. Remember to review the correctness of anydefaulted operations as you would any other code.

To eliminate the risk of slicing, prefer to make base classes abstract,by making their constructors protected, by declaring their destructors protected,or by giving them one or more pure virtual member functions. Prefer to avoidderiving from concrete classes.

Structs vs. Classes

Use astruct only for passive objects that carry data; everything else is aclass.

Thestruct andclasskeywords behave almost identically in C++. We add our ownsemantic meanings to each keyword, so you should use theappropriate keyword for the data-type you'redefining.

structs should be used for passive objects that carrydata, and may have associated constants. All fields must be public. Thestruct must not have invariants that imply relationships betweendifferent fields, since direct user access to those fields maybreak those invariants. Constructors, destructors, and helper methods maybe present; however, these methods must not require or enforce anyinvariants.

If more functionality or invariants are required, or struct has wide visibility and expected toevolve, then aclass is more appropriate. If in doubt, make it aclass.

For consistency with STL, you can usestruct instead ofclass forstateless types, such as traits,template metafunctions,and some functors.

Note that member variables in structs and classes havedifferent naming rules.

Structs vs. Pairs and Tuples

Prefer to use astruct instead of a pair or atuple whenever the elements can have meaningful names.

While using pairs and tuples can avoid the need to define a custom type, potentially saving work whenwriting code, a meaningful field name will almost always be much clearer whenreading code than.first,.second, orstd::get<X>. While C++14's introduction ofstd::get<Type> to access a tuple element by type rather than index (when the type is unique) can sometimes partially mitigate this, a field name is usually substantially clearer and more informative than a type.

Pairs and tuples may be appropriate in generic code where there are not specific meanings for the elements of the pair or tuple. Their use may also be required in order to interoperate with existing code or APIs.

Inheritance

Composition is often more appropriate than inheritance.When using inheritance, make itpublic.

When a sub-classinherits from a base class, it includes the definitionsof all the data and operations that the base classdefines. "Interface inheritance" is inheritance from apure abstract base class (one with no state or definedmethods); all other inheritance is "implementationinheritance".

Implementation inheritance reduces code size by re-usingthe base class code as it specializes an existing type.Because inheritance is a compile-time declaration, youand the compiler can understand the operation and detecterrors. Interface inheritance can be used toprogrammatically enforce that a class expose a particularAPI. Again, the compiler can detect errors, in this case,when a class does not define a necessary method of theAPI.

For implementation inheritance, because the codeimplementing a sub-class is spread between the base andthe sub-class, it can be more difficult to understand animplementation. The sub-class cannot override functionsthat are not virtual, so the sub-class cannot changeimplementation.

Multiple inheritance is especially problematic, becauseit often imposes a higher performance overhead (in fact,the performance drop from single inheritance to multipleinheritance can often be greater than the performancedrop from ordinary to virtual dispatch), and becauseit risks leading to "diamond" inheritance patterns,which are prone to ambiguity, confusion, and outright bugs.

All inheritance should bepublic. If youwant to do private inheritance, you should be includingan instance of the base class as a member instead. You may usefinal on classes when you don't intend to support usingthem as base classes.

Do not overuse implementation inheritance. Compositionis often more appropriate. Try to restrict use ofinheritance to the "is-a" case:BarsubclassesFoo if it can reasonably be saidthatBar "is a kind of"Foo.

Limit the use ofprotected to thosemember functions that might need to be accessed fromsubclasses. Note thatdatamembers should beprivate.

Explicitly annotate overrides of virtual functions or virtualdestructors with exactly one of anoverride or (lessfrequently)final specifier. Do notusevirtual when declaring an override.Rationale: A function or destructor markedoverride orfinal that isnot an override of a base class virtual function willnot compile, and this helps catch common errors. Thespecifiers serve as documentation; if no specifier ispresent, the reader has to check all ancestors of theclass in question to determine if the function ordestructor is virtual or not.

Multiple inheritance is permitted, but multipleimplementationinheritance is strongly discouraged.

Operator Overloading

Overload operators judiciously. Do not use user-defined literals.

C++ permits user code todeclareoverloaded versions of the built-in operators using theoperator keyword, so long as one of the parametersis a user-defined type. Theoperator keyword alsopermits user code to define new kinds of literals usingoperator"", and to define type-conversion functionssuch asoperator bool().

Operator overloading can make code more concise andintuitive by enabling user-defined types to behave the sameas built-in types. Overloaded operators are the idiomatic namesfor certain operations (e.g.,==,<,=, and<<), and adhering tothose conventions can make user-defined types more readableand enable them to interoperate with libraries that expectthose names.

User-defined literals are a very concise notation forcreating objects of user-defined types.

Define overloaded operators only if their meaning isobvious, unsurprising, and consistent with the correspondingbuilt-in operators. For example, use| as abitwise- or logical-or, not as a shell-style pipe.

Define operators only on your own types. More precisely,define them in the same headers,.cc files, and namespacesas the types they operate on. That way, the operators are availablewherever the type is, minimizing the risk of multipledefinitions. If possible, avoid defining operators as templates,because they must satisfy this rule for any possible templatearguments. If you define an operator, also defineany related operators that make sense, and make sure theyare defined consistently.

Prefer to define non-modifying binary operators asnon-member functions. If a binary operator is defined as aclass member, implicit conversions will apply to theright-hand argument, but not the left-hand one. It willconfuse your users ifa + b compiles butb + a doesn't.

For a typeT whose values can be compared forequality, define a non-memberoperator== and document whentwo values of typeT are considered equal.If there is a single obvious notion of when a valuet1of typeT is less than another such valuet2 thenyou may also defineoperator<=>, which should beconsistent withoperator==.Prefer not to overload the other comparison and ordering operators.

Don't go out of your way to avoid defining operatoroverloads. For example, prefer to define==,=, and<<, rather thanEquals(),CopyFrom(), andPrintTo(). Conversely, don't defineoperator overloads just because other libraries expectthem. For example, if your type doesn't have a naturalordering, but you want to store it in astd::set,use a custom comparator rather than overloading<.

Do not overload&&,||,, (comma), or unary&. Do not overloadoperator"", i.e., do not introduce user-definedliterals. Do not use any such literals provided by others(including the standard library).

Type conversion operators are covered in the section onimplicit conversions.The= operator is covered in the section oncopy constructors. Overloading<< for use with streams is covered in thesection onstreams. See also the rules onfunction overloading, whichapply to operator overloading as well.

Access Control

Make classes' data membersprivate, unless they areconstants. This simplifies reasoning about invariants, at the costof some easy boilerplate in the form of accessors (usuallyconst) if necessary.

For technicalreasons, we allow data members of a test fixture class defined in a.cc file tobeprotected when usingGoogleTest.If a test fixture class is defined outside of the.cc file it is used in, for examplein a.h file, make data membersprivate.

Declaration Order

Group similar declarations together, placingpublic partsearlier.

A class definition should usually start with apublic: section, followed byprotected:, thenprivate:. Omitsections that would be empty.

Within each section, prefer grouping similarkinds of declarations together, and prefer thefollowing order:

  1. Types and type aliases (typedef,using,enum, nested structs and classes, andfriend types)
  2. (Optionally, for structs only) non-static data members
  3. Static constants
  4. Factory functions
  5. Constructors and assignment operators
  6. Destructor
  7. All other functions (static and non-static member functions, andfriend functions)
  8. All other data members (static and non-static)

Do not put large method definitions inline in theclass definition. Usually, only trivial orperformance-critical, and very short, methods may bedefined inline. SeeInlineFunctions for more details.

Functions

Inputs and Outputs

The output of a C++ function is naturally provided viaa 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.SeeTotW #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 thefunction, or both. Non-optional input parameters should usually be valuesorconst references, while non-optional output andinput/output parameters should usually be references (which cannot be null).Generally, usestd::optional to represent optional by-valueinputs, and use aconst pointer when the non-optional form wouldhave used a reference. Use non-const pointers to representoptional 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 lifetimebugs. Instead, find a way to eliminate the lifetime requirement(for example, by copying the parameter), or pass retained parameters bypointer and document the lifetime and non-null requirements.SeeTotW 116 for more.

When ordering function parameters, put all input-onlyparameters before any output parameters. In particular,do not add new parameters to the end of the function justbecause they are new; place new input-only parameters beforethe output parameters. This is not a hard-and-fast rule. Parameters thatare 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

Prefer small and focused functions.

We recognize that long functions are sometimesappropriate, so no hard limit is placed on functionslength. If a function exceeds about 40 lines, think aboutwhether it can be broken up without harming the structureof the program.

Even if your long function works perfectly now,someone modifying it in a few months may add newbehavior. This could result in bugs that are hard tofind. Keeping your functions short and simple makes iteasier for other people to read and modify your code.Small functions are also easier to test.

You could find long and complicated functions whenworking withsome code. Do not beintimidated by modifying existing code: if working withsuch a function proves to be difficult, you find thaterrors are hard to debug, or you want to use a piece ofit in several different contexts, consider breaking upthe function into smaller and more manageable pieces.

Function Overloading

Use overloaded functions (including constructors) only if areader looking at a call site can get a good idea of whatis happening without having to first figure out exactlywhich overload is being called.

You may write a function that takes aconststd::string& and overload it with another thattakesconst char*. However, in this case considerstd::string_viewinstead.

class MyClass { public:  void Analyze(const std::string &text);  void Analyze(const char *text, size_t textlen);};

Overloading can make code more intuitive by allowing anidentically-named function to take different arguments.It may be necessary for templatized code, and it can beconvenient for Visitors.

Overloading based onconst or ref qualificationmay make utility code more usable, more efficient, or both.SeeTotW #148 for more.

If a function is overloaded by the argument types alone,a reader may have to understand C++'s complex matchingrules in order to tell what's going on. Also many peopleare confused by the semantics of inheritance if a derivedclass overrides only some of the variants of afunction.

You may overload a function when there are no semantic differencesbetween variants. These overloads may vary in types, qualifiers, orargument count. However, a reader of such a call must not need to knowwhich member of the overload set is chosen, only thatsomethingfrom the set is being called. If you can document all entries in theoverload set with a single comment in the header, that is a good signthat it is a well-designed overload set.

Default Arguments

Default arguments are allowed on non-virtual functionswhen the default is guaranteed to always have the samevalue. Follow the same restrictions as forfunction overloading, andprefer overloaded functions if the readability gained withdefault arguments doesn't outweigh the downsides below.

Often you have a function that uses default values, butoccasionally you want to override the defaults. Defaultparameters allow an easy way to do this without having todefine many functions for the rare exceptions. Comparedto overloading the function, default arguments have acleaner syntax, with less boilerplate and a clearerdistinction between 'required' and 'optional'arguments.

Defaulted arguments are another way to achieve thesemantics of overloaded functions, so all thereasons not to overloadfunctions apply.

The defaults for arguments in a virtual function call aredetermined by the static type of the target object, andthere's no guarantee that all overrides of a given functiondeclare the same defaults.

Default parameters are re-evaluated at each call site,which can bloat the generated code. Readers may also expectthe default's value to be fixed at the declaration insteadof varying at each call.

Function pointers are confusing in the presence ofdefault arguments, since the function signature oftendoesn't match the call signature. Addingfunction overloads avoids these problems.

Default arguments are banned on virtual functions, wherethey don't work properly, and in cases where the specifieddefault might not evaluate to the same value depending onwhen it was evaluated. (For example, don't writevoidf(int n = counter++);.)

In some other cases, default arguments can improve thereadability of their function declarations enough toovercome the downsides above, so they are allowed. When indoubt, use overloads.

Trailing Return Type Syntax

Use trailing return types only where using the ordinary syntax (leading return types) is impractical or much less readable.

C++ allows two different forms of function declarations. In the older form, the return type appears before the function name. For example:

int foo(int x);

The newer form uses theauto keyword before the function name and a trailing return type after the argument list. For example, the declaration above could equivalently be written:

auto foo(int x) -> int;

The trailing return type is in the function's scope. This doesn't make a difference for a simple case likeint but it matters for more complicated cases, like types declared in class scope or types written in terms of the function parameters.

Trailing return types are the only way to explicitly specify the return type of alambda expression. In some cases the compiler is able to deduce a lambda's return type, but not in all cases. Even when the compiler can deduce it automatically, sometimes specifying it explicitly would be clearer for readers.

Sometimes it's easier and more readable to specify a return type after the function's parameter list has already appeared. This is particularly true when the return type depends on template parameters. For example:

    template <typename T, typename U>    auto add(T t, U u) -> decltype(t + u);
versus
    template <typename T, typename U>    decltype(declval<T&>() + declval<U&>()) add(T t, U u);

Trailing return type syntax is relatively new and it has no analogue in C++-like languages such as C and Java, so some readers may find it unfamiliar.

Existing code bases have an enormous number of function declarations that aren't going to get changed to use the new syntax, so the realistic choices are using the old syntax only or using a mixture of the two. Using a single version is better for uniformity of style.

In most cases, continue to use the older style of function declaration where the return type goes before the function name. Use the new trailing-return-type form only in cases where it's required (such as lambdas) or where, by putting the type after the function's parameter list, it allows you to write the type in a much more readable way. The latter case should be rare; it's mostly an issue in fairly complicated template code, which isdiscouraged in most cases.

Google-Specific Magic

There are various tricks and utilities thatwe use to make C++ code more robust, and various ways we useC++ that may differ from what you see elsewhere.

Ownership and Smart Pointers

Prefer to have single, fixed owners for dynamicallyallocated objects. Prefer to transfer ownership with smartpointers.

"Ownership" is a bookkeeping technique for managingdynamically allocated memory (and other resources). Theowner of a dynamically allocated object is an object orfunction that is responsible for ensuring that it isdeleted when no longer needed. Ownership can sometimes beshared, in which case the last owner is typicallyresponsible for deleting it. Even when ownership is notshared, it can be transferred from one piece of code toanother.

"Smart" pointers are classes that act like pointers,e.g., by overloading the* and-> operators. Some smart pointer typescan be used to automate ownership bookkeeping, to ensurethese responsibilities are met.std::unique_ptr is a smart pointer typewhich expresses exclusive ownershipof a dynamically allocated object; the object is deletedwhen thestd::unique_ptr goes out of scope.It cannot be copied, but can bemoved torepresent ownership transfer.std::shared_ptr is a smart pointer typethat expresses shared ownership ofa dynamically allocated object.std::shared_ptrscan be copied; ownership of the object is shared amongall copies, and the object is deleted when the laststd::shared_ptr is destroyed.

If dynamic allocation is necessary, prefer to keepownership with the code that allocated it. If other codeneeds access to the object, consider passing it a copy,or passing a pointer or reference without transferringownership. Prefer to usestd::unique_ptr tomake ownership transfer explicit. For example:

std::unique_ptr<Foo> FooFactory();void FooConsumer(std::unique_ptr<Foo> ptr);

Do not design your code to use shared ownershipwithout a very good reason. One such reason is to avoidexpensive copy operations, but you should only do this ifthe performance benefits are significant, and theunderlying object is immutable (i.e.,std::shared_ptr<const Foo>). If youdo use shared ownership, prefer to usestd::shared_ptr.

Never usestd::auto_ptr. Instead, usestd::unique_ptr.

cpplint

Usecpplint.py to detect style errors.

cpplint.pyis a tool that reads a source file and identifies manystyle errors. It is not perfect, and has both falsepositives and false negatives, but it is still a valuabletool.

Some projects have instructions onhow to runcpplint.py from their projecttools. If the project you are contributing to does not,you can downloadcpplint.py separately.

Other C++ Features

Rvalue References

Use rvalue references only in certain special cases listed below.

Rvalue referencesare a type of reference that can only bind to temporaryobjects. The syntax is similar to traditional referencesyntax. For example,void f(std::string&&s); declares a function whose argument is anrvalue reference to astd::string.

When the token '&&' is applied toan unqualified template argument in a functionparameter, special template argument deductionrules apply. Such a reference is called a forwarding reference.

Do not use rvalue references (or apply the&&qualifier to methods), except as follows:

Friends

We allow use offriend classes and functions,within reason.

Friends should usually be defined in the same file sothat the reader does not have to look in another file tofind uses of the private members of a class. A common useoffriend is to have aFooBuilder class be a friend ofFoo so that it can construct the inner stateofFoo correctly, without exposing thisstate to the world. In some cases it may be useful tomake a unittest class a friend of the class it tests.

Friends extend, but do not break, the encapsulationboundary of a class. In some cases this is better thanmaking a memberpublic when you want to give only oneother class access to it. However, most classes shouldinteract with other classes solely through their publicmembers.

Exceptions

We do not use C++ exceptions.

On their face, the benefits of using exceptionsoutweigh the costs, especially in new projects. However,for existing code, the introduction of exceptions hasimplications on all dependent code. If exceptions can bepropagated beyond a new project, it also becomesproblematic to integrate the new project into existingexception-free code. Because most existing C++ code atGoogle is not prepared to deal with exceptions, it iscomparatively difficult to adopt new code that generatesexceptions.

Given that Google's existing code is notexception-tolerant, the costs of using exceptions aresomewhat greater than the costs in a new project. Theconversion process would be slow and error-prone. Wedon't believe that the available alternatives toexceptions, such as error codes and assertions, introducea significant burden.

Our advice against using exceptions is not predicatedon philosophical or moral grounds, but practical ones. Because we'd like to use our open-sourceprojects at Google and it's difficult to do so if thoseprojects use exceptions, we need to advise againstexceptions in Google open-source projects as well.Things would probably be different if we had to do it allover again from scratch.

This prohibition also applies to exception handling relatedfeatures such asstd::exception_ptr andstd::nested_exception.

There is anexception tothis rule (no pun intended) for Windows code.

noexcept

Specifynoexcept when it is useful and correct.

Thenoexcept specifier is used to specify whethera function will throw exceptions or not. If an exceptionescapes from a function markednoexcept, the programcrashes viastd::terminate.

Thenoexcept operator performs a compile-timecheck that returns true if an expression is declared to notthrow any exceptions.

You may usenoexcept when it is useful forperformance if it accurately reflects the intended semanticsof your function, i.e., that if an exception is somehow thrownfrom within the function body then it represents a fatal error.You can assume thatnoexcept on move constructorshas a meaningful performance benefit. If you thinkthere is significant performance benefit from specifyingnoexcept on some other function, please discuss itwithyour project leads.

Prefer unconditionalnoexcept if exceptions arecompletely disabled (i.e., most Google C++ environments).Otherwise, use conditionalnoexcept specifierswith simple conditions, in ways that evaluate false only inthe few cases where the function could potentially throw.The tests might include type traits check on whether theinvolved operation might throw (e.g.,std::is_nothrow_move_constructible formove-constructing objects), or on whether allocation can throw(e.g.,absl::default_allocator_is_nothrow forstandard default allocation). Note in many cases the onlypossible cause for an exception is allocation failure (webelieve move constructors should not throw except due toallocation failure), and there are many applications where it’sappropriate to treat memory exhaustion as a fatal error ratherthan an exceptional condition that your program should attemptto recover from. Even for otherpotential failures you should prioritize interface simplicityover supporting all possible exception throwing scenarios:instead of writing a complicatednoexcept clausethat depends on whether a hash function can throw, for example,simply document that your component doesn’t support hashfunctions throwing and make it unconditionallynoexcept.

Run-Time TypeInformation (RTTI)

Avoid using run-time type information (RTTI).

RTTI allows aprogrammer to query the C++ class of an object atrun-time. This is done by use oftypeid ordynamic_cast.

The standard alternatives to RTTI (described below)require modification or redesign of the class hierarchyin question. Sometimes such modifications are infeasibleor undesirable, particularly in widely-used or maturecode.

RTTI can be useful in some unit tests. For example, itis useful in tests of factory classes where the test hasto verify that a newly created object has the expecteddynamic type. It is also useful in managing therelationship between objects and their mocks.

RTTI is useful when considering multiple abstractobjects. Consider

bool Base::Equal(Base* other) = 0;bool Derived::Equal(Base* other) {  Derived* that = dynamic_cast<Derived*>(other);  if (that == nullptr)    return false;  ...}

Querying the type of an object at run-time frequentlymeans a design problem. Needing to know the type of anobject at runtime is often an indication that the designof your class hierarchy is flawed.

Undisciplined use of RTTI makes code hard to maintain.It can lead to type-based decision trees or switchstatements scattered throughout the code, all of whichmust be examined when making further changes.

RTTI has legitimate uses but is prone to abuse, so youmust be careful when using it. You may use it freely inunittests, but avoid it when possible in other code. Inparticular, think twice before using RTTI in new code. Ifyou find yourself needing to write code that behavesdifferently based on the class of an object, consider oneof the following alternatives to querying the type:

When the logic of a program guarantees that a giveninstance of a base class is in fact an instance of aparticular derived class, then adynamic_cast may be used freely on theobject. Usually onecan use astatic_cast as an alternative insuch situations.

Decision trees based on type are a strong indicationthat your code is on the wrong track.

if (typeid(*data) == typeid(D1)) {  ...} else if (typeid(*data) == typeid(D2)) {  ...} else if (typeid(*data) == typeid(D3)) {...

Code such as this usually breaks when additionalsubclasses are added to the class hierarchy. Moreover,when properties of a subclass change, it is difficult tofind and modify all the affected code segments.

Do not hand-implement an RTTI-like workaround. Thearguments against RTTI apply just as much to workaroundslike class hierarchies with type tags. Moreover,workarounds disguise your true intent.

Casting

Use C++-style castslikestatic_cast<float>(double_value), or braceinitialization for conversion of arithmetic types likeint64_t y = int64_t{1} << 42. Do not usecast formats like(int)x unless the cast is tovoid. You may use cast formats likeT(x) only whenT is a class type.

C++ introduced adifferent cast system from C that distinguishes the typesof cast operations.

The problem with C casts is the ambiguity of the operation;sometimes you are doing aconversion(e.g.,(int)3.5) and sometimes you are doingacast (e.g.,(int)"hello"). Braceinitialization and C++ casts can often help avoid thisambiguity. Additionally, C++ casts are more visible when searching forthem.

The C++-style cast syntax is verbose and cumbersome.

In general, do not use C-style casts. Instead, use these C++-stylecasts when explicit type conversion is necessary.

See theRTTI section for guidance on the use ofdynamic_cast.

Streams

Use streams where appropriate, and stick to "simple"usages. Overload<< for streaming only for typesrepresenting values, and write only the user-visible value, not anyimplementation details.

Streams are the standard I/O abstraction in C++, asexemplified by the standard header<iostream>.They are widely used in Google code, mostly for debug loggingand test diagnostics.

The<< and>>stream operators provide an API for formatted I/O thatis easily learned, portable, reusable, and extensible.printf, by contrast, doesn't even supportstd::string, to say nothing of user-defined types,and is very difficult to use portably.printf also obliges you to choose among thenumerous slightly different versions of that function,and navigate the dozens of conversion specifiers.

Streams provide first-class support for console I/Oviastd::cin,std::cout,std::cerr, andstd::clog.The C APIs do as well, but are hampered by the need tomanually buffer the input.

Use streams only when they are the best tool for the job.This is typically the case when the I/O is ad-hoc, local,human-readable, and targeted at other developers rather thanend-users. Be consistent with the code around you, and with thecodebase as a whole; if there's an established tool foryour problem, use that tool instead.In particular,logging libraries are usually a betterchoice thanstd::cerr orstd::clogfor diagnostic output, and the libraries inabsl/stringsor the equivalent are usually abetter choice thanstd::stringstream.

Avoid using streams for I/O that faces external users orhandles untrusted data. Instead, find and use the appropriatetemplating libraries to handle issues like internationalization,localization, and security hardening.

If you do use streams, avoid the stateful parts of thestreams API (other than error state), such asimbue(),xalloc(), andregister_callback().Use explicit formatting functions (such asabsl::StreamFormat()) rather thanstream manipulators or formatting flags to control formattingdetails such as number base, precision, or padding.

Overload<< as a streaming operatorfor your type only if your type represents a value, and<< writes out a human-readable stringrepresentation of that value. Avoid exposing implementationdetails in the output of<<; if you need to printobject internals for debugging, use named functions instead(a method namedDebugString() is the most commonconvention).

Preincrement and Predecrement

Use the prefix form (++i) of the incrementand decrement operators unless you need postfix semantics.

When a variableis incremented (++i ori++) ordecremented (--i ori--) andthe value of the expression is not used, one must decidewhether to preincrement (decrement) or postincrement(decrement).

A postfix increment/decrement expression evaluates to the valueas it was before it was modified. This can result in code that is morecompact but harder to read. The prefix form is generally more readable, isnever less efficient, and can be more efficient because it doesn't need tomake a copy of the value as it was before the operation.

The tradition developed, in C, of using post-increment, evenwhen the expression value is not used, especially infor loops.

Use prefix increment/decrement, unless the code explicitlyneeds the result of the postfix increment/decrement expression.

Use of const

In APIs, useconst whenever it makes sense.constexpr is a better choice for some uses ofconst.

Declared variables and parameters can be precededby the keywordconst to indicate the variablesare not changed (e.g.,const int foo). Classfunctions can have theconst qualifier toindicate the function does not change the state of theclass member variables (e.g.,class Foo { intBar(char c) const; };).

Easier for people to understand how variables are beingused. Allows the compiler to do better type checking,and, conceivably, generate better code. Helps peopleconvince themselves of program correctness because theyknow the functions they call are limited in how they canmodify your variables. Helps people know what functionsare safe to use without locks in multi-threadedprograms.

const is viral: if you pass aconst variable to a function, that functionmust haveconst in its prototype (or thevariable will need aconst_cast). This canbe a particular problem when calling libraryfunctions.

We strongly recommend usingconstin APIs (i.e., on function parameters, methods, andnon-local variables) wherever it is meaningful and accurate. Thisprovides consistent, mostly compiler-verified documentationof what objects an operation can mutate. Havinga consistent and reliable way to distinguish reads from writesis critical to writing thread-safe code, and is useful inmany other contexts as well. In particular:

Usingconst on local variables is neither encouragednor discouraged.

All of a class'sconst operations should be safeto invoke concurrently with each other. If that's not feasible, the class mustbe clearly documented as "thread-unsafe".

Where to put the const

Some people favor the formint const *footoconst int* foo. They argue that this ismore readable because it's more consistent: it keeps therule thatconst always follows the objectit's describing. However, this consistency argumentdoesn't apply in codebases with few deeply-nested pointerexpressions since mostconst expressionshave only oneconst, and it applies to theunderlying value. In such cases, there's no consistencyto maintain. Putting theconst first isarguably more readable, since it follows English inputting the "adjective" (const) before the"noun" (int).

That said, while we encourage puttingconst first, we do not require it. But beconsistent with the code around you!

Use of constexpr, constinit, and consteval

Useconstexpr to define trueconstants or to ensure constant initialization.Useconstinit to ensure constantinitialization for non-constant variables.

Some variables can be declaredconstexprto indicate the variables are true constants, i.e., fixed atcompilation/link time. Some functions and constructorscan be declaredconstexpr which enables themto be used in defining aconstexprvariable. Functions can be declaredconstevalto restrict their use to compile time.

Use ofconstexpr enables definition ofconstants with floating-point expressions rather thanjust literals; definition of constants of user-definedtypes; and definition of constants with functioncalls.

Prematurely marking something asconstexpr may causemigration problems if later on it has to be downgraded.Current restrictions on what is allowed inconstexprfunctions and constructors may invite obscure workaroundsin these definitions.

constexpr definitions enable a morerobust specification of the constant parts of aninterface. Useconstexpr to specify trueconstants and the functions that support theirdefinitions.consteval may be used forcode that must not be invoked at runtime.Avoid complexifying function definitions toenable their use withconstexpr. Do not useconstexpr orconsteval to force inlining.

Integer Types

Of the built-in C++ integer types, the only one used isint. If a program needs an integer type of adifferent size, use an exact-width integer type from<stdint.h>, such asint16_t. If you have avalue that could ever be greater than or equal to 2^31,use a 64-bit type such asint64_t.Keep in mind that even if your value won't ever be too largefor anint, it may be used in intermediatecalculations which may require a larger type. When in doubt,choose a larger type.

C++ does not specify exact sizes for the integer typeslikeint. Common sizes on contemporary architectures are16 bits forshort, 32 bits forint, 32 or 64bits forlong, and 64 bits forlong long,but different platforms make different choices, in particularforlong.

Uniformity of declaration.

The sizes of integral types in C++ can vary based oncompiler and architecture.

The standard library header<stdint.h> defines typeslikeint16_t,uint32_t,int64_t, etc. You should always usethose in preference toshort,unsignedlong long and the like, when you need a guaranteeon the size of an integer. Prefer to omit thestd::prefix for these types, as the extra 5 characters donot merit the added clutter. Of the built-in integer types, onlyint should be used. When appropriate, youare welcome to use standard type aliases likesize_t andptrdiff_t.

We useint very often, for integers weknow are not going to be too big, e.g., loop counters.Use plain oldint for such things. Youshould assume that anint isat least 32 bits, but don'tassume that it has more than 32 bits. If you need a 64-bitinteger type, useint64_t oruint64_t.

For integers we know can be "big", useint64_t.

You should not use the unsigned integer types such asuint32_t, unless there is a validreason such as representing a bit pattern rather than anumber, or you need defined overflow modulo 2^N. Inparticular, do not use unsigned types to say a numberwill never be negative. Instead, useassertions for this.

If your code is a container that returns a size, besure to use a type that will accommodate any possibleusage of your container. When in doubt, use a larger typerather than a smaller type.

Use care when converting integer types. Integer conversions andpromotions can cause undefined behavior, leading to security bugs andother problems.

On Unsigned Integers

Unsigned integers are good for representing bitfields and modulararithmetic. Because of historical accident, the C++ standard also usesunsigned integers to represent the size of containers - many membersof the standards body believe this to be a mistake, but it iseffectively impossible to fix at this point. The fact that unsignedarithmetic doesn't model the behavior of a simple integer, but isinstead defined by the standard to model modular arithmetic (wrappingaround on overflow/underflow), means that a significant class of bugscannot be diagnosed by the compiler. In other cases, the definedbehavior impedes optimization.

That said, mixing signedness of integer types is responsible for anequally large class of problems. The best advice we can provide: tryto use iterators and containers rather than pointers and sizes, trynot to mix signedness, and try to avoid unsigned types (except forrepresenting bitfields or modular arithmetic). Do not use an unsignedtype merely to assert that a variable is non-negative.

Floating-Point Types

Of the built-in C++ floating-point types, the only ones used arefloat anddouble. You may assume that these types represent IEEE-754 binary32and binary64, respectively.

Do not uselong double, as it gives non-portableresults.

Architecture Portability

Write architecture-portable code. Do not rely on CPU features specific to asingle processor.

Preprocessor Macros

Avoid defining macros, especially in headers; preferinline functions, enums, andconst variables.Name macros with a project-specific prefix. Do not usemacros to define pieces of a C++ API.

Macros mean that the code you see is not the same asthe code the compiler sees. This can introduce unexpectedbehavior, especially since macros have global scope.

The problems introduced by macros are especially severewhen they are used to define pieces of a C++ API,and still more so for public APIs. Every error message fromthe compiler when developers incorrectly use that interfacenow must explain how the macros formed the interface.Refactoring and analysis tools have a dramatically hardertime updating the interface. As a consequence, wespecifically disallow using macros in this way.For example, avoid patterns like:

class WOMBAT_TYPE(Foo) {  // ... public:  EXPAND_PUBLIC_WOMBAT_API(Foo)  EXPAND_WOMBAT_COMPARISONS(Foo, ==, <)};

Luckily, macros are not nearly as necessary in C++ asthey are in C. Instead of using a macro to inlineperformance-critical code, use an inline function.Instead of using a macro to store a constant, use aconst variable. Instead of using a macro to"abbreviate" a long variable name, use a reference.Instead of using a macro to conditionally compile code... well, don't do that at all (except, of course, forthe#define guards to prevent doubleinclusion of header files). It makes testing much moredifficult.

Macros can do things these other techniques cannot,and you do see them in the codebase, especially in thelower-level libraries. And some of their special features(like stringifying, concatenation, and so forth) are notavailable through the language proper. But before using amacro, consider carefully whether there's a non-macro wayto achieve the same result. If you need to use a macro todefine an interface, contactyour project leads to requesta waiver of this rule.

The following usage pattern will avoid many problemswith macros; if you use macros, follow it wheneverpossible:

Exporting macros from headers (i.e., defining them in a headerwithout#undefing them before the end of the header)is extremely strongly discouraged. If you do export a macro from aheader, it must have a globally unique name. To achieve this, itmust be named with a prefix consisting of your project's namespacename (but upper case).

0 and nullptr/NULL

Usenullptr for pointers, and'\0' for chars (andnot the0 literal).

For pointers (address values), usenullptr, as thisprovides type-safety.

Use'\0' for the null character. Using the correct type makesthe code more readable.

sizeof

Prefersizeof(varname) tosizeof(type).

Usesizeof(varname) when youtake the size of a particular variable.sizeof(varname) will updateappropriately if someone changes the variable type eithernow or later. You may usesizeof(type) for code unrelatedto any particular variable, such as code that manages anexternal or internal data format where a variable of anappropriate C++ type is not convenient.

MyStruct data;memset(&data, 0, sizeof(data));
memset(&data, 0, sizeof(MyStruct));
if (raw_size < sizeof(int)) {  LOG(ERROR) << "compressed record not big enough for count: " << raw_size;  return false;}

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.

There are several contexts in which C++ allows (or even requires) types tobe deduced by the compiler, rather than spelled out explicitly in the code:

Function template argument deduction
A function template can be invoked without explicit template arguments. The compiler deduces those arguments from the types of the function arguments:
template <typename T>void f(T t);f(0);  // Invokes f<int>(0)
auto variable declarations
A variable declaration can use theauto keyword in place of the type. The compiler deduces the type from the variable's initializer, following the same rules as function template argument deduction with the same initializer (so long as you don't use curly braces instead of parentheses).
auto a = 42;  // a is an intauto& b = a;  // b is an int&auto c = b;   // c is an intauto d{42};   // d is an int, not a std::initializer_list<int>
auto can be qualified withconst, and can be used as part of a pointer or reference type, and (since C++17) as a non-type template argument. A rare variant of this syntax usesdecltype(auto) instead ofauto, in which case the deduced type is the result of applyingdecltype to the initializer.
Function return type deduction
auto (anddecltype(auto)) can also be used in place of a function return type. The compiler deduces the return type from thereturn statements in the function body, following the same rules as for variable declarations:
auto f() { return 0; }  // The return type of f is int
Lambda expression return types can be deduced in the same way, but this is triggered by omitting the return type, rather than by an explicitauto. Confusingly,trailing return type syntax for functions also usesauto in the return-type position, but that doesn't rely on type deduction; it's just an alternate syntax for an explicit return type.
Generic lambdas
A lambda expression can use theauto keyword in place of 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 eachauto function parameter:
// Sort `vec` in decreasing orderstd::sort(vec.begin(), vec.end(), [](auto lhs, auto rhs) { return lhs > rhs; });
Lambda init captures
Lambda captures can have explicit initializers, which can be used to declare wholly new variables rather than only capturing existing ones:
[x = 42, y = "foo"] { ... }  // x is an int, and y is a const char*
This syntax doesn't allow the type to be specified; instead, it's deduced using the rules forauto variables.
Class template argument deduction
Seebelow.
Structured bindings
When declaring a tuple, struct, or array usingauto, you can specify names for the individual elements instead of a name for the whole object; these names are called "structured bindings", and the whole declaration is called a "structured binding declaration". This syntax provides no way of specifying the type of either the enclosing object or the individual names:
auto [iter, success] = my_map.insert({key, value});if (!success) {  iter->second = value;}
Theauto can also be qualified withconst,&, and&&, but note that these qualifiers technically apply to the anonymous tuple/struct/array, rather than the individual bindings. The rules that determine the types of the bindings are quite complex; the results tend to be unsurprising, except that 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.)

C++ code is usually clearer when types are explicit, especially when type deduction would depend on information from distant parts of the code. In expressions like:

auto foo = x.add_foo();auto i = y.Find(key);

it may not be obvious what the resulting types are if the type ofy isn't very well known, or ify was declared many lines earlier.

Programmers have to understand when type deduction will or won't produce a reference type, or they'll get copies when they didn't mean to.

If a deduced type is used as part of an interface, then a programmer might change its type while only intending to change its value, leading to a more radical API change than intended.

The fundamental rule is: use type deduction only to make the code clearer or safer, and do not use it merely to avoid the 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 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 ofMyWidgetFactory() probably isn't.

These principles apply to all forms of type deduction, but the details vary, as described in the following sections.

Function template argument deduction

Function template argument deduction is almost always OK. Type deduction is the expected default way of interacting with function templates, because it allows function templates to act like infinite sets of ordinary function overloads. Consequently, function templates are almost always designed so that template argument deduction is clear and safe, or doesn't compile.

Local variable type deduction

For local variables, you can use type deduction to make the code clearer by eliminating type information that is obvious or irrelevant, so that the reader can focus on the meaningful parts of the code:

std::unique_ptr<WidgetWithBellsAndWhistles> widget =    std::make_unique<WidgetWithBellsAndWhistles>(arg1, arg2);absl::flat_hash_map<std::string,                    std::unique_ptr<WidgetWithBellsAndWhistles>>::const_iterator    it = my_map_.find(key);std::array<int, 6> numbers = {4, 8, 15, 16, 23, 42};
auto widget = std::make_unique<WidgetWithBellsAndWhistles>(arg1, arg2);auto it = my_map_.find(key);std::array numbers = {4, 8, 15, 16, 23, 42};

Types sometimes contain a mixture of useful information and boilerplate, such asit in the example above: it's obvious that the type is an iterator, and in many contexts the container type and even the key type aren't relevant, but the type of the values is probably useful. In such situations, it's often possible to define local variables with explicit types that convey the relevant information:

if (auto it = my_map_.find(key); it != my_map_.end()) {  WidgetWithBellsAndWhistles& widget = *it->second;  // Do stuff with `widget`}

If the type is a template instance, and the parameters are boilerplate but the template itself is informative, you can use class template argument deduction to suppress the boilerplate. However, cases where this actually provides a meaningful benefit are quite rare. Note that class template argument deduction is also subject to aseparate style rule.

Do not usedecltype(auto) if a simpler option will work, because it's a fairly obscure feature, so it has a high cost in code clarity.

Return type deduction

Use return type deduction (for both functions and lambdas) only if the function body has a very small number ofreturn statements, and very little other code, because otherwise the reader may not be able to tell at a glance what the return type is. Furthermore, use it only if the function or lambda has a very narrow scope, because functions with deduced return types don't define abstraction boundaries: the implementationis the interface. In particular, public functions in header files should almost never have deduced return types.

Parameter type deduction

auto parameter types for lambdas should be used with caution, because the actual type is determined by the code that calls the lambda, rather than by the definition of the lambda. Consequently, an explicit 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., thestd::sort example above).

Lambda init captures

Init captures are covered by amore specific style rule, which largely supersedes the general rules for type deduction.

Structured bindings

Unlike other forms of type deduction, structured bindings can actually give the reader additional information, by giving meaningful names to the elements of a larger object. This means that a structured binding declaration may provide a net readability improvement over an explicit type, even in cases whereauto would not. Structured bindings are especially beneficial when the object is a pair or tuple (as in theinsert example above), because they don't have meaningful field names to begin with, but note that you generallyshouldn't use pairs or tuples unless a pre-existing API likeinsert forces you to.

If the object being bound is a struct, it may sometimes be helpful to provide names that are more specific to your usage, but keep in mind that this may also mean the names are less recognizable to your reader than the field names. We recommend using a comment to indicate the name of the underlying field, if it doesn't match the name of the binding, using the same syntax as for function parameter comments:

auto [/*field_name1=*/bound_name1, /*field_name2=*/bound_name2] = ...

As with function parameter comments, this can enable tools to detect if you get the order of the fields wrong.

Class Template Argument Deduction

Use class template argument deduction only with templates that have explicitly opted into supporting it.

Class template argument deduction (often abbreviated "CTAD") occurs when a variable is declared with a type that names a template, and the template argument list is not provided (not even empty angle brackets):

std::array a = {1, 2, 3};  // `a` is a std::array<int, 3>

The compiler deduces the arguments from the initializer using the template's "deduction guides", which can be explicit or implicit.

Explicit deduction guides look like function declarations with trailing return types, except that there's no leadingauto, and the function name is the name of the template. For example, the above example relies on this deduction guide forstd::array:

namespace std {template <class T, class... U>array(T, U...) -> std::array<T, 1 + sizeof...(U)>;}

Constructors in a primary template (as opposed to a template specialization) also implicitly define deduction guides.

When you declare a variable that relies on CTAD, the compiler selects a deduction guide using the rules of constructor overload resolution, and that guide's return type becomes the type of the variable.

CTAD can sometimes allow you to omit boilerplate from your code.

The implicit deduction guides that are generated from constructors may have undesirable behavior, or be outright incorrect. This is particularly problematic for constructors written before CTAD was introduced in C++17, because the authors of those constructors had no way of knowing about (much less fixing) any problems that their constructors would cause for CTAD. Furthermore, adding explicit deduction guides to fix those problems might break any existing code that relies on the implicit deduction guides.

CTAD also suffers from many of the same drawbacks asauto, because they are both mechanisms for deducing all or part of a variable's type from its initializer. CTAD does give the reader more information thanauto, but it also doesn't give the reader an obvious cue that information has been omitted.

Do not use CTAD with a given template unless the template's maintainers have opted into supporting use of CTAD by providing at least one explicit deduction guide (all templates in thestd namespace are also presumed to have opted in). This should be enforced with a compiler warning if available.

Uses of CTAD must also follow the general rules onType 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 readableaggregate expressions, especially for structs with less straightforwardordering of fields than thePoint example above.

While designated initializers have long been part of the C standard andsupported by C++ compilers as an extension, they were not supported byC++ prior to C++20.

The rules in the C++ standard are stricter than in C and compiler extensions,requiring that the designated initializers appear in the same order as thefields appear in the struct definition. So in the example above, it is legalaccording to C++20 to initializex and thenz, but noty and thenx.

Use designated initializers only in the form that is compatible with theC++20 standard: with initializers in the same order as the corresponding fieldsappear in the struct definition.

Lambda Expressions

Use lambda expressions where appropriate. Prefer explicit captureswhen the lambda will escape the current scope.

Lambda expressions are a concise way of creating anonymousfunction objects. They're often useful when passingfunctions as arguments. For example:

std::sort(v.begin(), v.end(), [](int x, int y) {  return Weight(x) < Weight(y);});

They further allow capturing variables from the enclosing scope eitherexplicitly by name, or implicitly using a default capture. Explicit capturesrequire each variable to be listed, aseither a value or reference capture:

int weight = 3;int sum = 0;// Captures `weight` by value and `sum` by reference.std::for_each(v.begin(), v.end(), [weight, &sum](int x) {  sum += weight * x;});

Default captures implicitly capture any variable referenced in thelambda body, includingthis if any members are used:

const std::vector<int> lookup_table = ...;std::vector<int> indices = ...;// Captures `lookup_table` by reference, sorts `indices` by the value// of the associated element in `lookup_table`.std::sort(indices.begin(), indices.end(), [&](int a, int b) {  return lookup_table[a] < lookup_table[b];});

A variable capture can also have an explicit initializer, which can be used for capturing move-only variables by value, or for other situations not handled by ordinary reference or value captures:

std::unique_ptr<Foo> foo = ...;[foo = std::move(foo)] () {  ...}

Such captures (often called "init captures" or "generalized lambda captures") need not actually "capture" anything from the enclosing scope, or even have a name from the enclosing scope; this syntax is a fully general way to define members of a lambda object:

[foo = std::vector<int>({1, 2, 3})] () {  ...}

The type of a capture with an initializer is deduced using the same rules asauto.

Template Metaprogramming

Avoid complicated template programming.

Template metaprogramming refers to a family of techniques thatexploit the fact that the C++ template instantiation mechanism isTuring complete and can be used to perform arbitrary compile-timecomputation in the type domain.

Template metaprogramming allows extremely flexible interfaces thatare type safe and high performance. Facilities likeGoogleTest,std::tuple,std::function, andBoost.Spirit would be impossible without it.

The techniques used in template metaprogramming are often obscureto anyone but language experts. Code that uses templates incomplicated ways is often unreadable, and is hard to debug ormaintain.

Template metaprogramming often leads to extremely poor compiletime error messages: even if an interface is simple, the complicatedimplementation details become visible when the user does somethingwrong.

Template metaprogramming interferes with large scale refactoring bymaking the job of refactoring tools harder. First, the template codeis expanded in multiple contexts, and it's hard to verify that thetransformation makes sense in all of them. Second, some refactoringtools work with an AST that only represents the structure of the codeafter template expansion. It can be difficult to automatically workback to the original source construct that needs to berewritten.

Template metaprogramming sometimes allows cleaner and easier-to-useinterfaces than would be possible without it, but it's also often atemptation to be overly clever. It's best used in a small number oflow level components where the extra maintenance burden is spread outover a large number of uses.

Think twice before using template metaprogramming or othercomplicated template techniques; think about whether the averagemember of your team will be able to understand your code well enoughto maintain it after you switch to another project, or whether anon-C++ programmer or someone casually browsing the code base will beable to understand the error messages or trace the flow of a functionthey want to call. If you're using recursive template instantiationsor type lists or metafunctions or expression templates, or relying onSFINAE or on thesizeof trick for detecting functionoverload resolution, then there's a good chance you've gone toofar.

If you use template metaprogramming, you should expect to putconsiderable effort into minimizing and isolating the complexity. Youshould hide metaprogramming as an implementation detail wheneverpossible, so that user-facing headers are readable, and you shouldmake sure that tricky code is especially well commented. You shouldcarefully document how the code is used, and you should say somethingabout what the "generated" code looks like. Pay extra attention to theerror messages that the compiler emits when users make mistakes. Theerror messages are part of your user interface, and your code shouldbe tweaked as necessary so that the error messages are understandableand actionable from a user point of view.

Concepts and Constraints

Use concepts sparingly.In general, concepts and constraints should only be used in caseswhere 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, andavoid thetemplate<Concept T> syntax;instead, use therequires(Concept<T>)syntax.

Theconcept keyword is a new mechanism for definingrequirements (such as type traits or interface specifications)for a template parameter.Therequires keyword provides mechanisms for placinganonymous constraints on templates and verifying that constraintsare satisfied at compile time.Concepts and constraints are often used together, but can bealso used independently.

Predefined concepts in the standard library should bepreferred to type traits, when equivalent ones exist.(e.g., ifstd::is_integral_v would have been usedbefore C++20, thenstd::integral should be used inC++20 code.)Similarly, prefer modern constraint syntax(viarequires(Condition)).Avoid legacy template metaprogramming constructs(such asstd::enable_if<Condition>)as well as thetemplate<Concept T>syntax.

Do not manually re-implement any existing concepts or traits.For example, userequires(std::default_initializable<T>)instead ofrequires(requires { T v; })or the like.

Newconcept declarations should be rare, and onlydefined internally within a library, such that they are notexposed at API boundaries.More generally, do not use concepts or constraints in cases whereyou wouldn't use their legacy template equivalents in C++17.

Do not define concepts that duplicate the function body,or impose requirements that would be insignificant or obviousfrom reading the body of the code or the resulting error messages.For example, avoid the following:

template <typename T>     // Bad - redundant with negligible benefitconcept Addable = std::copyable<T> && requires(T a, T b) { a + b; };template <Addable T>T Add(T x, T y, T z) { return x + y + z; }
Instead, prefer to leave code as an ordinary template unlessyou can demonstrate that concepts result in significantimprovement for that particular case, such as in the resultingerror messages for a deeply nested or non-obviousrequirement.

Concepts should be statically verifiable by the compiler.Do not use any concept whose primary benefits would come from asemantic (or otherwise unenforced) constraint.Requirements that are unenforced at compile time should insteadbe imposed via other mechanisms such as comments, assertions,or tests.

C++20 modules

Do not use C++20 Modules.

C++20 introduces "modules", a new language feature designed as analternative to textual inclusion of header files. It introduces threenew keywords to supportthis:module,export,andimport.

Modules are a big shift in how C++ is written and compiled, and weare still assessing how they may fit into Google's C++ ecosystem inthe future. Furthermore, they are not currently well-supported by ourbuild-systems, compilers, and other tooling, and need furtherexploration as to the best-practices when writing and using them.

Coroutines

Do not use coroutines (yet).

Do not include the<coroutine> header,or use theco_await,co_yield,orco_return keywords.

NOTE: this ban is expected to be temporary, while furtherguidance is being developed.

Boost

Use only approved libraries from the Boost librarycollection.

TheBoost library collection is a popular collection ofpeer-reviewed, free, open-source C++ libraries.

Boost code is generally very high-quality, is widelyportable, and fills many important gaps in the C++standard library, such as type traits and better binders.

Some Boost libraries encourage coding practices which canhamper readability, such as metaprogramming and otheradvanced template techniques, and an excessively"functional" style of programming.

In order to maintain a high level of readability forall contributors who might read and maintain code, weonly allow an approved subset of Boost features.Currently, the following libraries are permitted:

We are actively considering adding other Boostfeatures to the list, so this list may be expanded inthe future.

Disallowed standard library features

As withBoost, some modern C++library functionality encourages coding practices that hamperreadability—for example by removingchecked redundancy (such as type names) that may behelpful to readers, or by encouraging templatemetaprogramming. Other extensions duplicate functionalityavailable through existing mechanisms, which may lead to confusionand conversion costs.

The following C++ standard library features may not be used:

Nonstandard Extensions

Nonstandard extensions to C++ may not be used unless otherwise specified.

Compilers support various extensions that are not part of standard C++. Such extensions include GCC's__attribute__, intrinsic functions such as__builtin_prefetch or SIMD,#pragma, inline assembly,__COUNTER__,__PRETTY_FUNCTION__, compound statement expressions (e.g.,foo = ({ int x; Bar(&x); x }), variable-length arrays andalloca(), and the "Elvis Operator"a?:b.

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.

Aliases

Public aliases are for the benefit of an API's user, and should be clearly documented.

There are several ways to create names that are aliases of other entities:

using Bar = Foo;typedef Foo Bar;  // But prefer `using` in C++ code.using ::other_namespace::Foo;using enum MyEnumType;  // Creates aliases for all enumerators in MyEnumType.

In new code,using is preferable totypedef, because it provides a more consistent syntax with the rest of C++ and works with templates.

Like other declarations, aliases declared in a header file are part of that header's public API unless they're in a function definition, in the private portion of a class, or in an explicitly-marked internal namespace. Aliases in such areas or in.cc files are implementation details (because client code can't refer to them), and are not restricted by this rule.

Don't put an alias in your public API just to save typing in the implementation; do so only if you intend it to be used by your clients.

When defining a public alias, document the intent ofthe new name, including whether it is guaranteed to always be the same as the typeit's currently aliased to, or whether a more limited compatibility isintended. This lets the user know whether they can treat the types assubstitutable or whether more specific rules must be followed, and can help theimplementation retain some degree of freedom to change the alias.

Don't put namespace aliases in your public API. (See alsoNamespaces).

For example, these aliases document how they are intended to be used in client code:

namespace mynamespace {// Used to store field measurements. DataPoint may change from Bar* to some internal type.// Client code should treat it as an opaque pointer.using DataPoint = ::foo::Bar*;// A set of measurements. Just an alias for user convenience.using TimeSeries = std::unordered_set<DataPoint, std::hash<DataPoint>, DataPointComparator>;}  // namespace mynamespace

These aliases don't document intended use, and half of them aren't meant for client use:

namespace mynamespace {// Bad: none of these say how they should be used.using DataPoint = ::foo::Bar*;using ::std::unordered_set;  // Bad: just for local convenienceusing ::std::hash;           // Bad: just for local conveniencetypedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator> TimeSeries;}  // namespace mynamespace

However, local convenience aliases are fine in function definitions,private sections of classes, explicitly marked internal namespaces, and in.cc files:

// In a .cc fileusing ::foo::Bar;

Switch Statements

If not conditional on an enumerated value, switch statements should alwayshave adefault case (in the case of an enumerated value, thecompiler will warn you if any values are not handled). If the default caseshould never execute, treat this as an error. For example:

switch (var) {  case 0: {    ...    break;  }  case 1: {    ...    break;  }  default: {    LOG(FATAL) << "Invalid value in switch statement: " << var;  }}

Fall-through from one case label to another must be annotated using the[[fallthrough]]; attribute.[[fallthrough]]; shouldbe placed at a point of execution where a fall-through to the next case labeloccurs. A common exception is consecutive case labels without intervening code,in which case no annotation is needed.

switch (x) {  case 41:  // No annotation needed here.  case 43:    if (dont_be_picky) {      // Use this instead of or along with annotations in comments.      [[fallthrough]];    } else {      CloseButNoCigar();      break;    }  case 42:    DoSomethingSpecial();    [[fallthrough]];  default:    DoSomethingGeneric();    break;}

Inclusive Language

In all code, including naming and comments, use inclusive languageand avoid terms that other programmers might find disrespectful or offensive(such as "master" and "slave", "blacklist" and "whitelist", or "redline"),even if the terms also have an ostensibly neutral meaning.Similarly, use gender-neutral language unless you're referringto a specific person (and using their pronouns). For example,use "they"/"them"/"their" for people of unspecified gender(evenwhen singular), and "it"/"its" for software, computers, and otherthings that aren't people.

Naming

The most important consistency rules are those that governnaming. The style of a name immediately informs us what sort ofthing the named entity is: a type, a variable, a function, aconstant, a macro, etc., without requiring us to search for thedeclaration of that entity. The pattern-matching engine in ourbrains relies a great deal on these naming rules.

Style rules about naming are pretty arbitrary, but we feel thatconsistency is more important than individual preferences in thisarea, so regardless of whether you find them sensible or not,the rules are the rules.

For the purposes of the naming rules below, a "word" is anything that youwould write in English without internal spaces. Either words are all lowercase,with underscores between words("snake_case"), or wordsare mixed case with the first letter of each word capitalized("camelCase" or"PascalCase").

Choosing Names

Give things names that make their purpose or intent understandable to a newreader, even someone on a different team than the owners. Do not worry aboutsaving horizontal space as it is far more important to make your codeimmediately understandable by a new reader.

Consider the context in which the name will be used. A name should bedescriptive even if it is used far from the code that makes it available foruse. However, a name should not distract the reader by repeating informationthat's present in the immediate context. Generally, this means thatdescriptiveness should be proportional to the name's scope of visibility. A freefunction declared in a header should probably mention the header's library,while a local variable probably shouldn't explain what function it's within.

Minimize the use of abbreviations that would likely be unknown to someoneoutside your project (especially acronyms and initialisms). Do not abbreviate bydeleting letters within a word. When an abbreviation is used, prefer tocapitalize it as a single "word", e.g.,StartRpc() rather thanStartRPC(). As a rule of thumb, an abbreviation is probably OKif it's listed inWikipedia. Note that certain universally-known abbreviations are OK, such asi for a loop index andT for a templateparameter.

The names you see most frequently are not like most names; a small number of"vocabulary" names are reused so widely that they are always in context. Thesenames tend to be short or even abbreviated and their full meaning comes fromexplicit long-form documentation rather than from just comments on theirdefinition and the words within the names. E.g.absl::Status has adedicatedpagein a devguide,documenting its proper use. You probably won't define new vocabulary names veryoften, but if you do, getadditional design review to make sure the chosen names work well whenused widely.

class MyClass { public:  int CountFooErrors(const std::vector<Foo>& foos) {    int n = 0;  // Clear meaning given limited scope and context    for (const auto& foo : foos) {      ...      ++n;    }    return n;  }  // Function comment doesn't need to explain that this returns non-OK on  // failure as that is implied by the `absl::Status` return type, but it  // might document behavior for some specific codes.  absl::Status DoSomethingImportant() {    std::string fqdn = ...;  // Well-known abbreviation for Fully Qualified Domain Name    return absl::OkStatus();  } private:  const int kMaxAllowedConnections = ...;  // Clear meaning within context};
class MyClass { public:  int CountFooErrors(const std::vector<Foo>& foos) {    int total_number_of_foo_errors = 0;  // Overly verbose given limited scope and context    for (int foo_index = 0; foo_index < foos.size(); ++foo_index) {  // Use idiomatic `i`      ...      ++total_number_of_foo_errors;    }    return total_number_of_foo_errors;  }  // A return type with a generic name is unclear without widespread education.  Result DoSomethingImportant() {    int cstmr_id = ...;  // Deletes internal letters  } private:  const int kNum = ...;  // Unclear meaning within broad scope};

File Names

Filenames should be all lowercase and can includeunderscores (_) or dashes (-).Follow the convention that yourproject uses. If there is no consistentlocal pattern to follow, prefer "_".

Examples of acceptable file names:

C++ files should have a.cc filename extension, and header filesshould have a.h extension. Files that rely on being textually included at specific pointsshould end in.inc (see also the section onself-contained headers).

Do not use filenames that already exist in/usr/include, such asdb.h.

In general, make your filenames very specific. Forexample, usehttp_server_logs.h rather thanlogs.h. A very common case is to have a pairof files called, e.g.,foo_bar.h andfoo_bar.cc, defining a class calledFooBar.

Type Names

Type names start with a capital letter and have a capitalletter 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.Type names should start with a capital letter and have a capital letterfor each new word. No underscores. For example:

// classes and structsclass UrlTable { ...class UrlTableTester { ...struct UrlTableProperties { ...// typedefstypedef hash_map<UrlTableProperties *, std::string> PropertiesMap;// using aliasesusing PropertiesMap = hash_map<UrlTableProperties *, std::string>;// enumsenum class UrlTableError { ...

Concept Names

Concept names follow the same rules astype names.

Variable Names

The names of variables (including function parameters) and data members aresnake_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_.

Common Variable names

For example:

std::string table_name;  // OK - snake_case.
std::string tableName;   // Bad - mixed case.

Class Data Members

Data members of classes, both static and non-static, arenamed like ordinary nonmember variables, but with atrailing underscore. The exception to this is static constantclass members, which should follow the rules fornaming constants.

class TableInfo { public:  ...  static const int kTableVersion = 3;  // OK - constant naming.  ... private:  std::string table_name_;             // OK - underscore at end.  static Pool<TableInfo>* pool_;       // OK.};

Struct Data Members

Data members of structs, both static and non-static,are named like ordinary nonmember variables. They do not havethe trailing underscores that data members in classes have.

struct UrlTableProperties {  std::string name;  int num_entries;  static Pool<UrlTableProperties>* pool;};

SeeStructs vs.Classes for a discussion of when to use a structversus a class.

Constant Names

Variables declaredconstexpr orconst, and whose value is fixed forthe duration of the program, are named with a leading "k" followedby mixed case. Underscores can be used as separators in the rare caseswhere capitalization cannot be used for separation. For example:

const int kDaysInAWeek = 7;const int kAndroid8_0_0 = 24;  // Android 8.0.0

All such variables with static storage duration (i.e., statics and globals,seeStorage Duration for details) should be named this way, including those that are static constantclass data members and those in templates where different instantiations of the templatemay have different values. This convention is optional for variables of other storage classes,e.g., automatic variables; otherwise the usual variable naming rules apply. For example:

void ComputeFoo(absl::string_view suffix) {  // Either of these is acceptable.  const absl::string_view kPrefix = "prefix";  const absl::string_view prefix = "prefix";  ...}
void ComputeFoo(absl::string_view suffix) {  // Bad - different invocations of ComputeFoo give kCombined different values.  const std::string kCombined = absl::StrCat(kPrefix, suffix);  ...}

Function Names

Regular functions have mixed case; accessors and mutators may be namedlike variables.

Ordinarily, functions should start with a capital letter and have acapital letter for each new word.

AddTableEntry()DeleteUrl()OpenFileOrDie()

(The same naming rule applies to class- and namespace-scopeconstants that are exposed as part of an API and that are intended to looklike functions, because the fact that they're objects rather than functionsis an unimportant implementation detail.)

Accessors and mutators (get and set functions) may be named likevariables. These often correspond to actual member variables, but this isnot required. For example,int count() andvoidset_count(int count).

Namespace Names

Namespace names aresnake_case (all lowercase, with underscoresbetween words).

Whenchoosing names for namespaces, notethat names must be fully qualified when used in a header outside the namespace,becauseunqualified Aliases are generally banned.

Top-level namespaces must be globally unique and recognizable, so each oneshould be owned by a single project or team, with a name based on the name ofthat project or team. Usually, all code in the namespace should be under one ormore directories with the same name as the namespace.

Nested namespaces should avoid the names of well-known top-level namespaces,especiallystd andabsl, because in C++, nestednamespaces do not protect from collisions with names in other namespaces(seeTotW #130).

Enumerator Names

Enumerators (for both scoped and unscoped enums) should be named likeconstants, not likemacros. That is, usekEnumName notENUM_NAME.

enum class UrlTableError {  kOk = 0,  kOutOfMemory,  kMalformedInput,};
enum class AlternateUrlTableError {  OK = 0,  OUT_OF_MEMORY = 1,  MALFORMED_INPUT = 2,};

Until January 2009, the style was to name enum valueslikemacros. This causedproblems with name collisions between enum values andmacros. Hence, the change to prefer constant-style namingwas put in place. New code should use constant-stylenaming.

Template Parameter Names

Template parameters should follow the naming style for theircategory: type template parameters should follow the rules for namingtypes, and non-type templateparameters should follow the rules for namingvariables orconstants.

Macro Names

You're not really going todefine a macro, are you? If you do, they're like this:MY_MACRO_THAT_SCARES_SMALL_CHILDREN_AND_ADULTS_ALIKE.

Please see thedescriptionof macros; in general macros shouldnot be used.However, if they are absolutely needed, then they should benamed with all capitals and underscores, and with a project-specific prefix.

#define MYPROJECT_ROUND(x) ...

Aliases

The name for analias follows the same principles asany other new name, applied in the context where the alias is defined ratherthan where the original name appears.

Exceptions to Naming Rules

If you are naming something that is analogous to anexisting C or C++ entity then you can follow the existingnaming convention scheme.

bigopen()
function name, follows form ofopen()
uint
typedef
bigpos
struct orclass, follows form ofpos
sparse_hash_map
STL-like entity; follows STL naming conventions
LONGLONG_MAX
a constant, as inINT_MAX

Comments

Comments are absolutely vital to keeping our code readable. The following rules describe what youshould comment and where. But remember: while comments are very important, the best code isself-documenting. Giving sensible names to types and variables is much better than using obscurenames that you must then explain through comments.

When writing your comments, write for your audience: thenextcontributor who will need tounderstand your code. Be generous — the nextone may be you!

Comment Style

Use either the// or/* */syntax, as long as you are consistent.

While either syntax is acceptable,// ismuch more common. Be consistent with how youcomment and what style you use where.

File Comments

Start each file with license boilerplate.

If a source file (such as a.h file) declares multiple user-facing abstractions(common functions, related classes, etc.), include a comment describing the collection of thoseabstractions. Include enough detail for future authors to know what does not fit there. However,the detailed documentation about individual abstractions belongs with those abstractions, not at thefile level.

For instance, if you write a file comment forfrobber.h, you do not needto include a file comment infrobber.cc orfrobber_test.cc. On the other hand, if you write a collection of classes inregistered_objects.cc that has no associated header file, you must include a filecomment inregistered_objects.cc.

Legal Notice and Author Line

Every file should contain licenseboilerplate. Choose the appropriate boilerplate for thelicense used by the project (for example, Apache 2.0,BSD, LGPL, GPL).

If you make significant changes to a file with anauthor line, consider deleting the author line.New files should usually not contain copyright notice orauthor line.

Struct and Class Comments

Every non-obvious class or struct declaration should have anaccompanying comment that describes what it is for and how it shouldbe used.

// Iterates over the contents of a GargantuanTable.// Example://    std::unique_ptr<GargantuanTableIterator> iter = table->NewIterator();//    for (iter->Seek("foo"); !iter->done(); iter->Next()) {//      process(iter->key(), iter->value());//    }class GargantuanTableIterator {  ...};

Class Comments

The class comment should provide the reader with enough information to knowhow and when to use the class, as well as any additional considerationsnecessary to correctly use the class. Document the synchronization assumptionsthe class makes, if any. If an instance of the class can be accessed bymultiple threads, take extra care to document the rules and invariantssurrounding multithreaded use.

The class comment is often a good place for a small example code snippetdemonstrating a simple and focused usage of the class.

When sufficiently separated (e.g.,.h and.ccfiles), comments describing the use of the class should go together with itsinterface definition; comments about the class operation and implementationshould accompany the implementation of the class's methods.

Function Comments

Declaration comments describe use of the function (when it isnon-obvious); comments at the definition of a function describeoperation.

Function Declarations

Almost every function declaration should have comments immediatelypreceding it that describe what the function does and how to useit. These comments may be omitted only if the function is simple andobvious (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 ofThis function and should start with the verb phrase; for example,"Opens the file", rather than "Open the file". In general, these comments do notdescribe how the function performs its task. Instead, that should beleft to comments in the function definition.

Types of things to mention in comments at the functiondeclaration:

Here is an example:

// Returns an iterator for this table, positioned at the first entry// lexically greater than or equal to `start_word`. If there is no// such entry, returns a null pointer. The client must not use the// iterator after the underlying GargantuanTable has been destroyed.//// This method is equivalent to://    std::unique_ptr<Iterator> iter = table->NewIterator();//    iter->Seek(start_word);//    return iter;std::unique_ptr<Iterator> GetIterator(absl::string_view start_word) const;

However, do not be unnecessarily verbose or state thecompletely obvious.

When documenting function overrides, focus on thespecifics of the override itself, rather than repeatingthe comment from the overridden function. In many of thesecases, the override needs no additional documentation andthus no comment is required.

When commenting constructors and destructors, rememberthat the person reading your code knows what constructorsand destructors are for, so comments that just saysomething like "destroys this object" are not useful.Document what constructors do with their arguments (forexample, if they take ownership of pointers), and whatcleanup the destructor does. If this is trivial, justskip the comment. It is quite common for destructors notto have a header comment.

Function Definitions

If there is anything tricky about how a function doesits job, the function definition should have anexplanatory comment. For example, in the definitioncomment you might describe any coding tricks you use,give an overview of the steps you go through, or explainwhy you chose to implement the function in the way youdid rather than using a viable alternative. For instance,you might mention why it must acquire a lock for thefirst half of the function but why it is not needed forthe second half.

Note you shouldnot just repeat the commentsgiven with the function declaration, in the.h file or wherever. It's okay torecapitulate briefly what the function does, but thefocus of the comments should be on how it does it.

Variable Comments

In general the actual name of the variable should bedescriptive enough to give a good idea of what the variableis used for. In certain cases, more comments are required.

Class Data Members

The purpose of each class data member (also called an instancevariable or member variable) must be clear. If there are anyinvariants (special values, relationships between members, lifetimerequirements) not clearly expressed by the type and name, they must becommented. However, if the type and name suffice (intnum_events_;), no comment is needed.

In particular, add comments to describe the existence and meaningof sentinel values, such as nullptr or -1, when they are notobvious. For example:

private: // Used to bounds-check table accesses. -1 means // that we don't yet know how many entries the table has. int num_total_entries_;

Global Variables

All global variables should have a comment describing what theyare, what they are used for, and (if unclear) why they need to beglobal. For example:

// The total number of test cases that we run through in this regression test.const int kNumTestCases = 6;

Implementation Comments

In your implementation you should have comments in tricky,non-obvious, interesting, or important parts of your code.

Explanatory Comments

Tricky or complicated code blocks should have commentsbefore them.

Function Argument Comments

When the meaning of a function argument is nonobvious, considerone of the following remedies:

Consider the following example:
// What are these arguments?const DecimalNumber product = CalculateProduct(values, 7, false, nullptr);

versus:

ProductOptions options;options.set_precision_decimals(7);options.set_use_cache(ProductOptions::kDontUseCache);const DecimalNumber product =    CalculateProduct(values, options, /*completion_callback=*/nullptr);

Don'ts

Do not state the obvious. In particular, don't literally describe whatcode does, unless the behavior is nonobvious to a reader who understandsC++ well. Instead, provide higher level comments that describewhythe code does what it does, or make the code self describing.

Compare this:
// Find the element in the vector.  <-- Bad: obvious!if (std::find(v.begin(), v.end(), element) != v.end()) {  Process(element);}
To this:
// Process "element" unless it was already processed.if (std::find(v.begin(), v.end(), element) != v.end()) {  Process(element);}

Self-describing code doesn't need a comment. The comment fromthe example above would be obvious:

if (!IsAlreadyProcessed(element)) {  Process(element);}

Punctuation, Spelling, and Grammar

Pay attention to punctuation, spelling, and grammar; it iseasier to read well-written comments than badly writtenones.

Comments should be as readable as narrative text, withproper capitalization and punctuation. In many cases,complete sentences are more readable than sentencefragments. Shorter comments, such as comments at the endof a line of code, can sometimes be less formal, but youshould be consistent with your style.

Although it can be frustrating to have a code reviewerpoint out that you are using a comma when you should beusing a semicolon, it is very important that source codemaintain a high level of clarity and readability. Properpunctuation, spelling, and grammar help with thatgoal.

TODO Comments

UseTODO comments for code that is temporary,a short-term solution, or good-enough but not perfect.

TODOs should include the stringTODO in all caps, followed by thebug ID, name, e-mail address, or otheridentifierof the person or issue with the best contextabout the problem referenced by theTODO.

// TODO: bug 12345678 - Remove this after the 2047q4 compatibility window expires.// TODO: example.com/my-design-doc - Manually fix up this code the next time it's touched.// TODO(bug 12345678): Update this list after the Foo service is turned down.// TODO(John): Use a "\*" here for concatenation operator.

If yourTODO is of the form "At a futuredate do something" make sure that you either include avery specific date ("Fix by November 2005") or a veryspecific event ("Remove this code when all clients canhandle XML responses.").

Formatting

Coding style and formatting are pretty arbitrary, but aproject is much easier to followif everyone uses the same style. Individuals may not agree with everyaspect of the formatting rules, and some of the rules may takesome getting used to, but it is important that allproject contributors follow thestyle rules so thatthey can all read and understandeveryone's code easily.

To help you format code correctly, we've created asettings file for emacs.

Line Length

Each line of text in your code should be at most 80characters long.

We recognize that this rule iscontroversial, but so much existing code already adheresto it, and we feel that consistency is important.

Those who favor this ruleargue that it is rude to force them to resizetheir windows and there is no need for anything longer.Some folks are used to having several code windowsside-by-side, and thus don't have room to widen theirwindows in any case. People set up their work environmentassuming a particular maximum window width, and 80columns has been the traditional standard. Why changeit?

Proponents of change argue that a wider line can makecode more readable. The 80-column limit is an hideboundthrowback to 1960s mainframes; modern equipment has wide screens thatcan easily show longer lines.

80 characters is the maximum.

A line may exceed 80 characters if it is

Non-ASCII Characters

Non-ASCII characters should be rare, and must use UTF-8formatting.

You shouldn't hard-code user-facing text in source,even English, so use of non-ASCII characters should berare. However, in certain cases it is appropriate toinclude such words in your code. For example, if yourcode parses data files from foreign sources, it may beappropriate to hard-code the non-ASCII string(s) used inthose data files as delimiters. More commonly, unittestcode (which does not need to be localized) mightcontain non-ASCII strings. In such cases, you should useUTF-8, since that is an encodingunderstood by most tools able to handle more than justASCII.

Hex encoding is also OK, and encouraged where itenhances readability — for example,"\xEF\xBB\xBF", or, even more simply,"\uFEFF", is the Unicode zero-widthno-break space character, which would be invisibleif included in the source as straight UTF-8.

When possible, avoid theu8 prefix.It has significantly different semantics starting in C++20than in C++17, producing arrays ofchar8_trather thanchar, and will change again in C++23.

You shouldn't usechar16_t andchar32_t character types, since they're fornon-UTF-8 text. For similar reasons you also shouldn'tusewchar_t (unless you're writing code thatinteracts with the Windows API, which useswchar_t extensively).

Spaces vs. Tabs

Use only spaces, and indent 2 spaces at a time.

We use spaces for indentation. Do not use tabs in yourcode. You should set your editor to emit spaces when youhit the tab key.

Function Declarations and Definitions

Return type on the same line as function name, parameterson the same line if they fit. Wrap parameter lists which donot fit on a single line as you would wrap arguments in afunction call.

Functions look like this:

ReturnType ClassName::FunctionName(Type par_name1, Type par_name2) {  DoSomething();  ...}

If you have too much text to fit on one line:

ReturnType ClassName::ReallyLongFunctionName(Type par_name1, Type par_name2,                                             Type par_name3) {  DoSomething();  ...}

or if you cannot fit even the first parameter:

ReturnType LongClassName::ReallyReallyReallyLongFunctionName(    Type par_name1,  // 4 space indent    Type par_name2,    Type par_name3) {  DoSomething();  // 2 space indent  ...}

Some points to note:

Unused parameters that are obvious from context may be omitted:

class Foo { public:  Foo(const Foo&) = delete;  Foo& operator=(const Foo&) = delete;};

Unused parameters that might not be obvious should comment out the variablename in the function definition:

class Shape { public:  virtual void Rotate(double radians) = 0;};class Circle : public Shape { public:  void Rotate(double radians) override;};void Circle::Rotate(double /*radians*/) {}
// Bad - if someone wants to implement later, it's not clear what the// variable means.void Circle::Rotate(double) {}

Attributes, and macros that expand to attributes, appear at the verybeginning of the function declaration or definition, before thereturn type:

  ABSL_ATTRIBUTE_NOINLINE void ExpensiveFunction();  [[nodiscard]] bool IsOk();

Lambda Expressions

Format parameters and bodies as for any other function, and capturelists like other comma-separated lists.

For by-reference captures, do not leave a space between theampersand (&) and the variable name.

int x = 0;auto x_plus_n = [&x](int n) -> int { return x + n; }

Short lambdas may be written inline as function arguments.

absl::flat_hash_set<int> to_remove = {7, 8, 9};std::vector<int> digits = {3, 9, 1, 8, 4, 7, 1};digits.erase(std::remove_if(digits.begin(), digits.end(), [&to_remove](int i) {               return to_remove.contains(i);             }),             digits.end());

Floating-point Literals

Floating-point literals should always have a radix point, with digits on bothsides, even if they use exponential notation. Readability is improved if allfloating-point literals take this familiar form, as this helps ensure that theyare not mistaken for integer literals, and that theE/e of the exponential notation is not mistaken for ahexadecimal digit. It is fine to initialize a floating-point variable with aninteger literal (assuming the variable type can exactly represent that integer),but note that a number in exponential notation is never an integer literal.

float f = 1.f;long double ld = -.5L;double d = 1248e6;
float f = 1.0f;float f2 = 1.0;  // Also OKfloat f3 = 1;    // Also OKlong double ld = -0.5L;double d = 1248.0e6;

Function Calls

Either write the call all on a single line, wrap thearguments at the parenthesis, or start the arguments on a newline indented by four spaces and continue at that 4 spaceindent. In the absence of other considerations, use theminimum number of lines, including placing multiple argumentson each line where appropriate.

Function calls have the following format:

bool result = DoSomething(argument1, argument2, argument3);

If the arguments do not all fit on one line, theyshould be broken up onto multiple lines, with eachsubsequent line aligned with the first argument. Do notadd spaces after the open paren or before the closeparen:

bool result = DoSomething(averyveryveryverylongargument1,                          argument2, argument3);

Arguments may optionally all be placed on subsequentlines with a four space indent:

if (...) {  ...  ...  if (...) {    bool result = DoSomething(        argument1, argument2,  // 4 space indent        argument3, argument4);    ...  }

Put multiple arguments on a single line to reduce thenumber of lines necessary for calling a function unlessthere is a specific readability problem. Some find thatformatting with strictly one argument on each line ismore readable and simplifies editing of the arguments.However, we prioritize for the reader over the ease ofediting arguments, and most readability problems arebetter addressed with the following techniques.

If having multiple arguments in a single line decreasesreadability due to the complexity or confusing nature of theexpressions that make up some arguments, try creatingvariables that capture those arguments in a descriptive name:

int my_heuristic = scores[x] * y + bases[x];bool result = DoSomething(my_heuristic, x, y, z);

Or put the confusing argument on its own line withan explanatory comment:

bool result = DoSomething(scores[x] * y + bases[x],  // Score heuristic.                          x, y, z);

If there is still a case where one argument issignificantly more readable on its own line, then put it onits own line. The decision should be specific to the argumentwhich is made more readable rather than a general policy.

Sometimes arguments form a structure that is importantfor readability. In those cases, feel free to format thearguments according to that structure:

// Transform the widget by a 3x3 matrix.my_widget.Transform(x1, x2, x3,                    y1, y2, y3,                    z1, z2, z3);

Braced Initializer List Format

Format a braced initializer list exactly like you would format a functioncall in its place.

If the braced list follows a name (e.g., a type orvariable name), format as if the{} were theparentheses of a function call with that name. If thereis no name, assume a zero-length name.

// Examples of braced init list on a single line.return {foo, bar};functioncall({foo, bar});std::pair<int, int> p{foo, bar};// When you have to wrap.SomeFunction(    {"assume a zero-length name before {"},    some_other_function_parameter);SomeType variable{    some, other, values,    {"assume a zero-length name before {"},    SomeOtherType{        "Very long string requiring the surrounding breaks.",        some, other, values},    SomeOtherType{"Slightly shorter string",                  some, other, values}};SomeType variable{    "This is too long to fit all in one line"};MyType m = {  // Here, you could also break before {.    superlongvariablename1,    superlongvariablename2,    {short, interior, list},    {interiorwrappinglist,     interiorwrappinglist2}};

Looping and branching statements

At a high level, looping or branching statements consist of the followingcomponents:

For these statements:
if (condition) {                   // Good - no spaces inside parentheses, space before brace.  DoOneThing();                    // Good - two-space indent.  DoAnotherThing();} else if (int a = f(); a != 3) {  // Good - closing brace on new line, else on same line.  DoAThirdThing(a);} else {  DoNothing();}// Good - the same rules apply to loops.while (condition) {  RepeatAThing();}// Good - the same rules apply to loops.do {  RepeatAThing();} while (condition);// Good - the same rules apply to loops.for (int i = 0; i < 10; ++i) {  RepeatAThing();}
if(condition) {}                   // Bad - space missing after `if`.else if ( condition ) {}           // Bad - space between the parentheses and the condition.else if (condition){}              // Bad - space missing before `{`.else if(condition){}               // Bad - multiple spaces missing.for (int a = f();a == 10) {}       // Bad - space missing after the semicolon.// Bad - `if ... else` statement does not have braces everywhere.if (condition)  foo;else {  bar;}// Bad - `if` statement too long to omit braces.if (condition)  // Comment  DoSomething();// Bad - `if` statement too long to omit braces.if (condition1 &&    condition2)  DoSomething();

For historical reasons, we allow one exception to the above rules: the curlybraces for the controlled statement or the line breaks inside the curly bracesmay be omitted if as a result the entire statement appears on either a singleline (in which case there is a space between the closing parenthesis and thecontrolled statement) or on two lines (in which case there is a line breakafter the closing parenthesis and there are no braces).

// OK - fits on one line.if (x == kFoo) { return new Foo(); }// OK - braces are optional in this case.if (x == kFoo) return new Foo();// OK - condition fits on one line, body fits on another.if (x == kBar)  Bar(arg1, arg2, arg3);

This exception does not apply to multi-keyword statements likeif ... else ordo ... while.

// Bad - `if ... else` statement is missing braces.if (x) DoThis();else DoThat();// Bad - `do ... while` statement is missing braces.do DoThis();while (x);

Use this style only when the statement is brief, and consider that loops andbranching statements with complex conditions or controlled statements may bemore readable with curly braces. Someprojects require curly braces always.

case blocks inswitch statements can have curlybraces or not, depending on your preference. If you do include curly braces,they should be placed as shown below.

switch (var) {  case 0: {  // 2 space indent    Foo();   // 4 space indent    break;  }  default: {    Bar();  }}

Empty loop bodies should use either an empty pair of braces orcontinue with no braces, rather than a single semicolon.

while (condition) {}  // Good - `{}` indicates no logic.while (condition) {  // Comments are okay, too}while (condition) continue;  // Good - `continue` indicates no logic.
while (condition);  // Bad - looks like part of `do-while` loop.

Pointer and Reference Expressions

No spaces around period or arrow. Pointer operators do nothave trailing spaces.

The following are examples of correctly-formattedpointer and reference expressions:

x = *p;p = &x;x = r.y;x = r->y;

Note that:

When referring to a pointer or reference (variable declarations or definitions, arguments,return types, template parameters, etc), you may place the space before or after theasterisk/ampersand. In the trailing-space style, the space is elided in some cases (templateparameters, etc).

// These are fine, space preceding.char *c;const std::string &str;int *GetPointer();std::vector<char *>// These are fine, space following (or elided).char* c;const std::string& str;int* GetPointer();std::vector<char*>  // Note no space between '*' and '>'

You should do this consistently within a singlefile.When modifying an existing file, use the style inthat file.

It is allowed (if unusual) to declare multiple variables in the samedeclaration, but it is disallowed if any of those have pointer orreference decorations. Such declarations are easily misread.

// Fine if helpful for readability.int x, y;
int x, *y;  // Disallowed - no & or * in multiple declarationint* x, *y;  // Disallowed - no & or * in multiple declaration; inconsistent spacingchar * c;  // Bad - spaces on both sides of *const std::string & str;  // Bad - spaces on both sides of &

Boolean Expressions

When you have a boolean expression that is longer than thestandard line length, beconsistent in how you break up the lines.

In this example, the logical AND operator is always atthe end of the lines:

if (this_one_thing > this_other_thing &&    a_third_thing == a_fourth_thing &&    yet_another && last_one) {  ...}

Note that when the code wraps in this example, both ofthe&& logical AND operators are atthe end of the line. This is more common in Google code,though wrapping all operators at the beginning of theline is also allowed. Feel free to insert extraparentheses judiciously because they can be very helpfulin increasing readability when usedappropriately, but be careful about overuse. Also note that youshould always use the punctuation operators, such as&& and~, rather thanthe word operators, such asand andcompl.

Return Values

Do not needlessly surround thereturnexpression with parentheses.

Use parentheses inreturn expr; onlywhere you would use them inx = expr;.

return result;                  // No parentheses in the simple case.// Parentheses OK to make a complex expression more readable.return (some_long_condition &&        another_condition);
return (value);                // You wouldn't write var = (value);return(result);                // return is not a function!

Variable and Array Initialization

You may choose between=,(), and{}; the following areall correct:

int x = 3;int x(3);int x{3};std::string name = "Some Name";std::string name("Some Name");std::string name{"Some Name"};

Be careful when using a braced initialization list{...}on a type with anstd::initializer_list constructor.A nonemptybraced-init-list prefers thestd::initializer_list constructor wheneverpossible. Note that empty braces{} are special, andwill call a default constructor if available. To force thenon-std::initializer_list constructor, use parenthesesinstead of braces.

std::vector<int> v(100, 1);  // A vector containing 100 items: All 1s.std::vector<int> v{100, 1};  // A vector containing 2 items: 100 and 1.

Also, the brace form prevents narrowing of integraltypes. This can prevent some types of programmingerrors.

int pi(3.14);  // OK -- pi == 3.int pi{3.14};  // Compile error: narrowing conversion.

Preprocessor Directives

The hash mark that starts a preprocessor directive shouldalways be at the beginning of the line.

Even when preprocessor directives are within the bodyof indented code, the directives should start at thebeginning of the line.

// Good - directives at beginning of line  if (lopsided_score) {#if DISASTER_PENDING      // Correct -- Starts at beginning of line    DropEverything();# if NOTIFY               // OK but not required -- Spaces after #    NotifyClient();# endif#endif    BackToNormal();  }
// Bad - indented directives  if (lopsided_score) {    #if DISASTER_PENDING  // Wrong!  The "#if" should be at beginning of line    DropEverything();    #endif                // Wrong!  Do not indent "#endif"    BackToNormal();  }

Class Format

Sections inpublic,protected andprivate order, each indented one space.

The basic format for a class definition (lacking thecomments, seeClassComments for a discussion of what comments areneeded) is:

class MyClass : public OtherClass { public:      // Note the 1 space indent!  MyClass();  // Regular 2 space indent.  explicit MyClass(int var);  ~MyClass() {}  void SomeFunction();  void SomeFunctionThatDoesNothing() {  }  void set_some_var(int var) { some_var_ = var; }  int some_var() const { return some_var_; } private:  bool SomeInternalFunction();  int some_var_;  int some_other_var_;};

Things to note:

Constructor Initializer Lists

Constructor initializer lists can be all on one line orwith subsequent lines indented four spaces.

The acceptable formats for initializer lists are:

// When everything fits on one line:MyClass::MyClass(int var) : some_var_(var) {  DoSomething();}// If the signature and initializer list are not all on one line,// you must wrap before the colon and indent 4 spaces:MyClass::MyClass(int var)    : some_var_(var), some_other_var_(var + 1) {  DoSomething();}// When the list spans multiple lines, put each member on its own line// and align them:MyClass::MyClass(int var)    : some_var_(var),             // 4 space indent      some_other_var_(var + 1) {  // lined up  DoSomething();}// As with any other code block, the close curly can be on the same// line as the open curly, if it fits.MyClass::MyClass(int var)    : some_var_(var) {}

Namespace Formatting

The contents of namespaces are not indented.

Namespaces do not add anextra level of indentation. For example, use:

namespace {void foo() {  // Correct.  No extra indentation within namespace.  ...}}  // namespace

Do not indent within a namespace:

namespace {  // Wrong!  Indented when it should not be.  void foo() {    ...  }}  // namespace

Horizontal Whitespace

Use of horizontal whitespace depends on location. Never puttrailing whitespace at the end of a line.

General

int i = 0;  // Two spaces before end-of-line comments.void f(bool b) {  // Open braces should always have a space before them.  ...int i = 0;  // Semicolons usually have no space before them.// Spaces inside braces for braced-init-list are optional.  If you use them,// put them on both sides!int x[] = { 0 };int x[] = {0};// Spaces around the colon in inheritance and initializer lists.class Foo : public Bar { public:  // For inline function implementations, put spaces between the braces  // and the implementation itself.  Foo(int b) : Bar(), baz_(b) {}  // No spaces inside empty braces.  void Reset() { baz_ = 0; }  // Spaces separating braces from implementation.  ...

Adding trailing whitespace can cause extra work forothers editing the same file, when they merge, as canremoving existing trailing whitespace. So: Don'tintroduce trailing whitespace. Remove it if you'realready changing that line, or do it in a separateclean-upoperation (preferably when no-oneelse is working on the file).

Loops and Conditionals

if (b) {          // Space after the keyword in conditions and loops.} else {          // Spaces around else.}while (test) {}   // There is usually no space inside parentheses.switch (i) {for (int i = 0; i < 5; ++i) {// Loops and conditions may have spaces inside parentheses, but this// is rare.  Be consistent.switch ( i ) {if ( test ) {for ( int i = 0; i < 5; ++i ) {// For loops always have a space after the semicolon.  They may have a space// before the semicolon, but this is rare.for ( ; i < 5 ; ++i) {  ...// Range-based for loops always have a space before and after the colon.for (auto x : counts) {  ...}switch (i) {  case 1:         // No space before colon in a switch case.    ...  case 2: break;  // Use a space after a colon if there's code after it.

Operators

// Assignment operators always have spaces around them.x = 0;// Other binary operators usually have spaces around them, but it's// OK to remove spaces around factors.  Parentheses should have no// internal padding.v = w * x + y / z;v = w*x + y/z;v = w * (x + z);// No spaces separating unary operators and their arguments.x = -5;++x;if (x && !y)  ...

Templates and Casts

// No spaces inside the angle brackets (< and >), before// <, or between >( in a caststd::vector<std::string> x;y = static_cast<char*>(x);// Spaces between type and pointer are OK, but be consistent.std::vector<char *> x;

Vertical Whitespace

Minimize use of vertical whitespace.

This is more a principle than a rule: don't use blank lines whenyou don't have to. In particular, don't put more than one or two blanklines between functions, resist starting functions with a blank line,don't end functions with a blank line, and be sparing with your use ofblank lines. A blank line within a block of code serves like aparagraph break in prose: visually separating two thoughts.

The basic principle is: The more code that fits on one screen, theeasier it is to follow and understand the control flow of theprogram. Use whitespace purposefully to provide separation in thatflow.

Some rules of thumb to help when blank lines may beuseful:

Exceptions to the Rules

The coding conventions described above are mandatory.However, like all good rules, these sometimes have exceptions,which we discuss here.

Existing Non-conformant Code

You may diverge from the rules when dealing with code thatdoes not conform to this style guide.

If you find yourself modifying code that was writtento specifications other than those presented by thisguide, you may have to diverge from these rules in orderto stay consistent with the local conventions in thatcode. If you are in doubt about how to do this, ask theoriginal author or the person currently responsible forthe code. Remember thatconsistency includeslocal consistency, too.

Windows Code

Windowsprogrammers have developed their own set of codingconventions, mainly derived from the conventions in Windowsheaders and other Microsoft code. We want to make it easyfor anyone to understand your code, so we have a single setof guidelines for everyone writing C++ on any platform.

It is worth reiterating a few of the guidelines thatyou might forget if you are used to the prevalent Windowsstyle:

However, there are just a few rules that weoccasionally need to break on Windows:


[8]ページ先頭

©2009-2025 Movatter.jp