Google C++ Style Guide
+ + +Background
+ +C++ is one of the main development languages used by +many of Google's open-source projects. As every C++ +programmer knows, the language has many powerful features, but +this power brings with it complexity, which in turn can make +code more bug-prone and harder to read and maintain.
+ +The goal of this guide is to manage this complexity by +describing in detail the dos and don'ts of writing C++ code. +These rules exist to +keep the code base manageable while still allowing +coders to use C++ language features productively.
+ +Style, also known as readability, is what we call +the conventions that govern our C++ code. The term Style is a +bit of a misnomer, since these conventions cover far more than +just source file formatting.
+ ++Most open-source projects developed by +Google conform to the requirements in this guide. +
+ + + + + +Note that this guide is not a C++ tutorial: we assume that +the 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 should +serve. These are the fundamental whys that +underlie all of the individual rules. By bringing these ideas to +the fore, we hope to ground discussions and make it clearer to our +broader community why the rules are in place and why particular +decisions have been made. If you understand what goals each rule is +serving, it should be clearer to everyone when a rule may be waived +(some can be), and what sort of argument or alternative would be +necessary 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 rule
+must be large enough to justify asking all of our engineers to
+remember it. The benefit is measured relative to the codebase we would
+get without the rule, so a rule against a very harmful practice may
+still have a small benefit if people are unlikely to do it
+anyway. This principle mostly explains the rules we don’t have, rather
+than the rules we do: for example,
goto
contravenes many +of the following principles, but is already vanishingly rare, so the Style +Guide doesn’t discuss it.
+
+ - Optimize for the reader, not the writer +
- Our codebase (and most individual components submitted to it) is
+expected to continue for quite some time. As a result, more time will
+be spent reading most of our code than writing it. We explicitly
+choose to optimize for the experience of our average software engineer
+reading, maintaining, and debugging code in our codebase rather than
+ease when writing said code. "Leave a trace for the reader" is a
+particularly common sub-point of this principle: When something
+surprising or unusual is happening in a snippet of code (for example,
+transfer of pointer ownership), leaving textual hints for the reader
+at the point of use is valuable (
std::unique_ptr
+demonstrates the ownership transfer unambiguously at the call +site).
+
+ - Be consistent with existing code +
- Using one style consistently through our codebase lets us focus on
+other (more important) issues. Consistency also allows for
+automation: tools that format your code or adjust
+your
#include
s only work properly when your code is +consistent with the expectations of the tooling. In many cases, rules +that are attributed to "Be Consistent" boil down to "Just pick one and +stop worrying about it"; the potential value of allowing flexibility +on these points is outweighed by the cost of having people argue over +them.
+
+ - Be consistent with the broader C++ community when appropriate +
- Consistency with the way other organizations use C++ has value for +the same reasons as consistency within our code base. If a feature in +the C++ standard solves a problem, or if some idiom is widely known +and accepted, that's an argument for using it. However, sometimes +standard features and idioms are flawed, or were just designed without +our codebase's needs in mind. In those cases (as described below) it's +appropriate to constrain or ban standard features. In some cases we +prefer a homegrown or third-party library over a library defined in +the C++ Standard, either out of perceived superiority or insufficient +value to transition the codebase to the standard interface. + +
- Avoid surprising or dangerous constructs +
- C++ has features that are more surprising or dangerous than one +might think at a glance. Some style guide restrictions are in place to +prevent falling into these pitfalls. There is a high bar for style +guide waivers on such restrictions, because waiving such rules often +directly risks compromising program correctness. + + +
- Avoid constructs that our average C++ programmer would find tricky +or hard to maintain +
- C++ has features that may not be generally appropriate because of +the complexity they introduce to the code. In widely used +code, it may be more acceptable to use +trickier language constructs, because any benefits of more complex +implementation are multiplied widely by usage, and the cost in understanding +the complexity does not need to be paid again when working with new +portions of the codebase. When in doubt, waivers to rules of this type +can be sought by asking +your project leads. This is specifically +important for our codebase because code ownership and team membership +changes over time: even if everyone that works with some piece of code +currently understands it, such understanding is not guaranteed to hold a +few 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 costly +for many. For instance it's particularly important to +avoid polluting the global namespace: name collisions across a +codebase of hundreds of millions of lines are difficult to work with +and hard to avoid if everyone puts things into the global +namespace. + +
- Concede to optimization when necessary +
- Performance optimizations can sometimes be necessary and +appropriate, even when they conflict with the other principles of this +document. +
The intent of this document is to provide maximal guidance with +reasonable restriction. As always, common sense and good taste should +prevail. By this we specifically refer to the established conventions +of the entire Google C++ community, not just your personal preferences +or those of your team. Be skeptical about and reluctant to use +clever or unusual constructs: the absence of a prohibition is not the +same as a license to proceed. Use your judgment, and if you are +unsure, please don't hesitate to ask your project leads to get additional +input.
+ +Header Files
+ +In general, every .cc
file should have an
+associated .h
file. There are some common
+exceptions, such as unittests and
+small .cc
files containing just a
+main()
function.
Correct use of header files can make a huge difference to +the readability, size and performance of your code.
+ +The following rules will guide you through the various +pitfalls of using header files.
+ + +Self-contained Headers
+ +Header files should be self-contained (compile on their own) and
+end in .h
. Non-header files that are meant for inclusion
+should end in .inc
and be used sparingly.
All header files should be self-contained. Users and refactoring +tools should not have to adhere to special conditions to include the +header. Specifically, a header should +have header guards and include all +other headers it needs.
+ +Prefer placing the definitions for template and inline functions in
+the same file as their declarations. The definitions of these
+constructs must be included into every .cc
file that uses
+them, or the program may fail to link in some build configurations. If
+declarations and definitions are in different files, including the
+former should transitively include the latter. Do not move these
+definitions to separately included header files (-inl.h
);
+this practice was common in the past, but is no longer allowed.
As an exception, a template that is explicitly instantiated for
+all relevant sets of template arguments, or that is a private
+implementation detail of a class, is allowed to be defined in the one
+and only .cc
file that instantiates the template.
There are rare cases where a file designed to be included is not
+self-contained. These are typically intended to be included at unusual
+locations, such as the middle of another file. They might not
+use header guards, and might not include
+their prerequisites. Name such files with the .inc
+extension. Use sparingly, and prefer self-contained headers when
+possible.
The #define Guard
+ +All header files should have #define
guards to
+prevent multiple inclusion. The format of the symbol name
+should be
+<PROJECT>_<PATH>_<FILE>_H_
.
To guarantee uniqueness, they should
+be based on the full path in a project's source tree. For
+example, the file foo/src/bar/baz.h
in
+project foo
should have the following
+guard:
#ifndef FOO_BAR_BAZ_H_ +#define FOO_BAR_BAZ_H_ + +... + +#endif // FOO_BAR_BAZ_H_ ++ + + + +
Forward Declarations
+ +Avoid using forward declarations where possible.
+ Just #include
the headers you need.
A "forward declaration" is a declaration of a class, +function, or template without an associated definition.
+-
+
- Forward declarations can save compile time, as
+
#include
s force the compiler to open + more files and process more input.
+
+ - Forward declarations can save on unnecessary
+ recompilation.
#include
s can force + your code to be recompiled more often, due to unrelated + changes in the header.
+
-
+
- Forward declarations can hide a dependency, allowing + user code to skip necessary recompilation when headers + change. + +
- A forward declaration may be broken by subsequent + changes to the library. Forward declarations of functions + and templates can prevent the header owners from making + otherwise-compatible changes to their APIs, such as + widening a parameter type, adding a template parameter + with a default value, or migrating to a new namespace. + +
- Forward declaring symbols from namespace
+
std::
yields undefined behavior.
+
+ - It can be difficult to determine whether a forward
+ declaration or a full
#include
is needed. + Replacing an#include
with a forward + declaration can silently change the meaning of + code: +// b.h: + struct B {}; + struct D : B {}; + + // good_user.cc: + #include "b.h" + void f(B*); + void f(void*); + void test(D* x) { f(x); } // calls f(B*) +
+ If the#include
was replaced with forward + decls forB
andD
, +test()
would callf(void*)
. +
+
+ - Forward declaring multiple symbols from a header
+ can be more verbose than simply
+
#include
ing the header.
+
+ - Structuring code to enable forward declarations + (e.g. using pointer members instead of object members) + can make the code slower and more complex. + + +
-
+
- Try to avoid forward declarations of entities + defined in another project. + +
- When using a function declared in a header file,
+ always
#include
that header.
+
+ - When using a class template, prefer to
+
#include
its header file.
+
Please see Names and Order +of Includes for rules about when to #include a header.
+Inline Functions
+ +Define functions inline only when they are small, say, 10 +lines or fewer.
+You can declare functions in a way that allows the compiler to expand +them inline rather than calling them through the usual +function call mechanism.
+Inlining a function can generate more efficient object +code, as long as the inlined function is small. Feel free +to inline accessors and mutators, and other short, +performance-critical functions.
+Overuse of inlining can actually make programs slower. +Depending on a function's size, inlining it can cause the +code size to increase or decrease. Inlining a very small +accessor function will usually decrease code size while +inlining a very large function can dramatically increase +code size. On modern processors smaller code usually runs +faster due to better use of the instruction cache.
+A decent rule of thumb is to not inline a function if +it is more than 10 lines long. Beware of destructors, +which are often longer than they appear because of +implicit member- and base-destructor calls!
+ +Another useful rule of thumb: it's typically not cost +effective to inline functions with loops or switch +statements (unless, in the common case, the loop or +switch statement is never executed).
+ +It is important to know that functions are not always +inlined even if they are declared as such; for example, +virtual and recursive functions are not normally inlined. +Usually recursive functions should not be inline. The +main reason for making a virtual function inline is to +place its definition in the class, either for convenience +or to document its behavior, e.g., for accessors and +mutators.
+Names and Order of Includes
+ +Use standard order for readability and to avoid hidden
+dependencies: Related header, C library, C++ library, other libraries'
+.h
, your project's .h
.
+All of a project's header files should be
+listed as descendants of the project's source
+directory without use of UNIX directory shortcuts
+.
(the current directory) or ..
+(the parent directory). For example,
+
+google-awesome-project/src/base/logging.h
+should be included as:
#include "base/logging.h" ++ +
In dir/foo.cc
or
+dir/foo_test.cc
, whose main
+purpose is to implement or test the stuff in
+dir2/foo2.h
, order your includes
+as follows:
-
+
dir2/foo2.h
.
+
+ - C system files. + +
- C++ system files. + +
- Other libraries'
.h
+ files.
+
+ -
+ Your project's
.h
+ files.
+
With the preferred ordering, if
+dir2/foo2.h
omits any necessary
+includes, the build of dir/foo.cc
+or dir/foo_test.cc
will break.
+Thus, this rule ensures that build breaks show up first
+for the people working on these files, not for innocent
+people in other packages.
dir/foo.cc
and
+dir2/foo2.h
are usually in the same
+directory (e.g. base/basictypes_test.cc
and
+base/basictypes.h
), but may sometimes be in different
+directories too.
Within each section the includes should be ordered +alphabetically. Note that older code might not conform to +this rule and should be fixed when convenient.
+ +You should include all the headers that define the symbols you rely
+upon, except in the unusual case of forward
+declaration. If you rely on symbols from bar.h
,
+don't count on the fact that you included foo.h
which
+(currently) includes bar.h
: include bar.h
+yourself, unless foo.h
explicitly demonstrates its intent
+to provide you the symbols of bar.h
. However, any
+includes present in the related header do not need to be included
+again in the related cc
(i.e., foo.cc
can
+rely on foo.h
's includes).
For example, the includes in
+
+google-awesome-project/src/foo/internal/fooserver.cc
+might look like this:
#include "foo/server/fooserver.h" + +#include <sys/types.h> +#include <unistd.h> + +#include <hash_map> +#include <vector> + +#include "base/basictypes.h" +#include "base/commandlineflags.h" +#include "foo/server/bar.h" ++ +
Sometimes, system-specific code needs +conditional includes. Such code can put conditional +includes after other includes. Of course, keep your +system-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. Namespaces
+should have unique names based on the project name, and possibly
+its path. Do not use using-directives (e.g.
+using namespace foo
). Do not use
+inline namespaces. For unnamed namespaces, see
+Unnamed Namespaces and
+Static Variables.
+
Namespaces subdivide the global scope +into distinct, named scopes, and so are useful for preventing +name collisions in the global scope.
+Namespaces provide a method for preventing name conflicts +in large programs while allowing most code to use reasonably +short names.
+ +For example, if two different projects have a class
+Foo
in the global scope, these symbols may
+collide at compile time or at runtime. If each project
+places their code in a namespace, project1::Foo
+and project2::Foo
are now distinct symbols that
+do not collide, and code within each project's namespace
+can continue to refer to Foo
without the prefix.
Inline namespaces automatically place their names in +the enclosing scope. Consider the following snippet, for +example:
+ +namespace X { +inline namespace Y { + void foo(); +} // namespace Y +} // namespace X ++ +
The expressions X::Y::foo()
and
+X::foo()
are interchangeable. Inline
+namespaces are primarily intended for ABI compatibility
+across versions.
Namespaces can be confusing, because they complicate +the mechanics of figuring out what definition a name refers +to.
+ +Inline namespaces, in particular, can be confusing +because names aren't actually restricted to the namespace +where they are declared. They are only useful as part of +some larger versioning policy.
+ +In some contexts, it's necessary to repeatedly refer to +symbols by their fully-qualified names. For deeply-nested +namespaces, this can add a lot of clutter.
+Namespaces should be used as follows:
+ +-
+
- Follow the rules on Namespace Names. +
- Terminate namespaces with comments as shown in the given examples. +
-
+
+
Namespaces wrap the entire source file after + includes, + + gflags definitions/declarations + and forward declarations of classes from other namespaces.
+ +// In the .h file +namespace mynamespace { + +// All declarations are within the namespace scope. +// Notice the lack of indentation. +class MyClass { + public: + ... + void Foo(); +}; + +} // namespace mynamespace +
+ +// In the .cc file +namespace mynamespace { + +// Definition of functions is within scope of the namespace. +void MyClass::Foo() { + ... +} + +} // namespace mynamespace +
+ +More complex
+ +.cc
files might have additional details, + like flags or using-declarations.#include "a.h" + +DEFINE_FLAG(bool, someflag, false, "dummy flag"); + +namespace a { + +using ::foo::bar; + +...code for a... // Code goes against the left margin. + +} // namespace a +
+
+
+
+
+ - Do not declare anything in namespace
+
std
, including forward declarations of + standard library classes. Declaring entities in + namespacestd
is undefined behavior, i.e., + not portable. To declare entities from the standard + library, include the appropriate header file.
+
+ You may not use a using-directive + to make all names from a namespace available.
+ +// Forbidden -- This pollutes the namespace. +using namespace foo; +
+
+
+ Do not use Namespace aliases at namespace scope + in header files except in explicitly marked + internal-only namespaces, because anything imported into a namespace + in a header file becomes part of the public + API exported by that file.
+ +// Shorten access to some commonly used names in .cc files. +namespace baz = ::foo::bar::baz; +
+ +// Shorten access to some commonly used names (in a .h file). +namespace librarian { +namespace impl { // Internal, not part of the API. +namespace sidetable = ::pipeline_diagnostics::sidetable; +} // namespace impl + +inline void my_inline_function() { + // namespace alias local to a function (or method). + namespace baz = ::foo::bar::baz; + ... +} +} // namespace librarian +
+ +- Do not use inline namespaces. +
Unnamed Namespaces and Static +Variables
+ +When definitions in a .cc
file do not need to be
+referenced outside that file, place them in an unnamed
+namespace or declare them static
. Do not use either
+of these constructs in .h
files.
+
All declarations can be given internal linkage by placing them in
+unnamed namespaces, and functions and variables can be given internal linkage by
+declaring them static
. This means that anything you're declaring
+can't be accessed from another file. If a different file declares something
+with the same name, then the two entities are completely independent.
Use of internal linkage in .cc
files is encouraged
+for 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 global +functions rarely. Prefer grouping functions with a namespace instead of +using a class as if it were a namespace. Static methods of a class should +generally be closely related to instances of the class or the class's static +data.
+Nonmember and static member functions can be useful in + some situations. Putting nonmember functions in a + namespace avoids polluting the global namespace.
+Nonmember and static member functions may make more sense +as members of a new class, especially if they access +external resources or have significant dependencies.
+Sometimes it is useful to define a
+function not bound to a class instance. Such a function
+can be either a static member or a nonmember function.
+Nonmember functions should not depend on external
+variables, and should nearly always exist in a namespace.
+Rather than creating classes only to group static member
+functions which do not share static data, use
+namespaces instead. For a header
+myproject/foo_bar.h
, for example, write
namespace myproject { +namespace foo_bar { +void Function1(); +void Function2(); +} // namespace foo_bar +} // namespace myproject ++
instead of
+namespace myproject { +class FooBar { + public: + static void Function1(); + static void Function2(); +}; +} // namespace myproject ++ +
If you define a nonmember function and it is only
+needed in its .cc
file, use
+internal linkage to limit
+its scope.
Local Variables
+ +Place a function's variables in the narrowest scope +possible, and initialize variables in the declaration.
+C++ allows you to declare variables anywhere in a +function. We encourage you to declare them in as local a +scope as possible, and as close to the first use as +possible. This makes it easier for the reader to find the +declaration and see what type the variable is and what it +was initialized to. In particular, initialization should +be used instead of declaration and assignment, e.g.:
+ +int i; +i = f(); // Bad -- initialization separate from declaration. ++ +
int j = g(); // Good -- declaration has initialization. ++ +
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 for if
, while
+and for
statements should normally be declared
+within those statements, so that such variables are confined
+to those scopes. E.g.:
while (const char* p = strchr(str, '/')) str = p + 1; ++ +
There is one caveat: if the variable is an object, its +constructor is invoked every time it enters scope and is +created, and its destructor is invoked every time it goes +out 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 variable +used 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
+ +Variables of class type with
+ static storage duration are forbidden: they cause hard-to-find bugs due
+ to indeterminate order of construction and destruction. However, such
+ variables are allowed if they are constexpr
: they have no
+ dynamic initialization or destruction.
Objects with static storage duration, including global +variables, static variables, static class member +variables, and function static variables, must be Plain +Old Data (POD): only ints, chars, floats, or pointers, or +arrays/structs of POD.
+ +The order in which class constructors and initializers +for static variables are called is only partially +specified in C++ and can even change from build to build, +which can cause bugs that are difficult to find. +Therefore in addition to banning globals of class type, +we do not allow non-local static variables to be initialized +with the result of a function, unless that function (such +as getenv(), or getpid()) does not itself depend on any +other globals. However, a static POD variable within +function scope may be initialized with the result of a +function, since its initialization order is well-defined +and does not occur until control passes through its +declaration.
+ +Likewise, global and static variables are destroyed
+when the program terminates, regardless of whether the
+termination is by returning from main()
or
+by calling exit()
. The order in which
+destructors are called is defined to be the reverse of
+the order in which the constructors were called. Since
+constructor order is indeterminate, so is destructor
+order. For example, at program-end time a static variable
+might have been destroyed, but code still running
+— perhaps in another thread
+— tries to access it and fails. Or the
+destructor for a static string
variable
+might be run prior to the destructor for another variable
+that contains a reference to that string.
One way to alleviate the destructor problem is to
+terminate the program by calling
+quick_exit()
instead of exit()
.
+The difference is that quick_exit()
does not
+invoke destructors and does not invoke any handlers that
+were registered by calling atexit()
. If you
+have a handler that needs to run when a program
+terminates via quick_exit()
(flushing logs,
+for example), you can register it using
+at_quick_exit()
. (If you have a handler that
+needs to run at both exit()
and
+quick_exit()
, you need to register it in
+both places.)
As a result we only allow static variables to contain
+POD data. This rule completely disallows
+std::vector
(use C arrays instead), or
+string
(use const char []
).
If you need a static or global +variable of a class type, consider initializing a pointer +(which will never be freed), from either your main() +function or from pthread_once(). Note that this must be a +raw pointer, not a "smart" pointer, since the smart +pointer's destructor will have the order-of-destructor +issue that we are trying to avoid.
+ + + + + +Classes
+ +Classes are the fundamental unit of code in C++. Naturally, +we use them extensively. This section lists the main dos and +don'ts you should follow when writing a class.
+ +Doing Work in Constructors
+ +Avoid virtual method calls in constructors, and avoid +initialization that can fail if you can't signal an error.
+It is possible to perform arbitrary initialization in the body +of the constructor.
+-
+
- No need to worry about whether the class has been initialized or + not. + +
- Objects that are fully initialized by constructor call can
+ be
const
and may also be easier to use with standard containers + or algorithms.
+
-
+
- If the work calls virtual functions, these calls + will not get dispatched to the subclass + implementations. Future modification to your class can + quietly introduce this problem even if your class is + not currently subclassed, causing much confusion. + +
- There is no easy way for constructors to signal errors, short of + crashing the program (not always appropriate) or using exceptions + (which are forbidden). + +
- If the work fails, we now have an object whose initialization
+ code failed, so it may be an unusual state requiring a
bool + IsValid()
state checking mechanism (or similar) which is easy + to forget to call.
+
+ - You cannot take the address of a constructor, so whatever work + is done in the constructor cannot easily be handed off to, for + example, another thread. +
Constructors should never call virtual functions. If appropriate
+for your code
+,
+terminating the program may be an appropriate error handling
+response. Otherwise, consider a factory function
+or Init()
method. Avoid Init()
methods on objects with
+no other states that affect which public methods may be called
+(semi-constructed objects of this form are particularly hard to work
+with correctly).
Implicit Conversions
+ +Do not define implicit conversions. Use the explicit
+keyword for conversion operators and single-argument
+constructors.
Implicit conversions allow an
+object of one type (called the source type) to
+be used where a different type (called the destination
+type) is expected, such as when passing an
+int
argument to a function that takes a
+double
parameter.
In addition to the implicit conversions defined by the language,
+users can define their own, by adding appropriate members to the
+class definition of the source or destination type. An implicit
+conversion in the source type is defined by a type conversion operator
+named after the destination type (e.g. operator
+bool()
). An implicit conversion in the destination
+type is defined by a constructor that can take the source type as
+its only argument (or only argument with no default value).
The explicit
keyword can be applied to a constructor
+or (since C++11) a conversion operator, to ensure that it can only be
+used when the destination type is explicit at the point of use,
+e.g. with a cast. This applies not only to implicit conversions, but to
+C++11's list 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 the +language treats it as one as far as
explicit
is concerned.
+-
+
- Implicit conversions can make a type more usable and + expressive by eliminating the need to explicitly name a type + when it's obvious. +
- Implicit conversions can be a simpler alternative to + overloading. +
- List initialization syntax is a concise and expressive + way of initializing objects. +
-
+
- Implicit conversions can hide type-mismatch bugs, where the + destination type does not match the user's expectation, or + the user is unaware that any conversion will take place. + +
- Implicit conversions can make code harder to read, particularly + in the presence of overloading, by making it less obvious what + code is actually getting called. + +
- Constructors that take a single argument may accidentally + be usable as implicit type conversions, even if they are not + intended to do so. + +
- When a single-argument constructor is not marked
+
explicit
, there's no reliable way to tell whether + it's intended to define an implicit conversion, or the author + simply forgot to mark it.
+
+ - It's not always clear which type should provide the conversion, + and if they both do, the code becomes ambiguous. + +
- List initialization can suffer from the same problems if + the destination type is implicit, particularly if the + list has only a single element. +
Type conversion operators, and constructors that are
+callable with a single argument, must be marked
+explicit
in the class definition. As an
+exception, copy and move constructors should not be
+explicit
, since they do not perform type
+conversion. Implicit conversions can sometimes be necessary and
+appropriate for types that are designed to transparently wrap other
+types. In that case, contact
+your project leads to request
+a waiver of this rule.
Constructors that cannot be called with a single argument
+should usually omit explicit
. Constructors that
+take a single std::initializer_list
parameter should
+also omit explicit
, in order to support copy-initialization
+(e.g. MyType m = {1, 2};
).
Copyable and Movable Types
+ +Support copying and/or moving if these operations are clear and meaningful +for your type. Otherwise, disable the implicitly generated special functions +that perform copies and moves. +
A copyable type allows its objects to be initialized or assigned
+from any other object of the same type, without changing the value of the source.
+For user-defined types, the copy behavior is defined by the copy
+constructor and the copy-assignment operator.
+string
is an example of a copyable type.
A movable type is one that can be initialized and assigned
+from temporaries (all copyable types are therefore movable).
+std::unique_ptr<int>
is an example of a movable but not
+copyable type. For user-defined types, the move behavior is defined by the move
+constructor and the move-assignment operator.
The copy/move constructors can be implicitly invoked by the compiler +in 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 objects +by pointer or reference, there's no risk of confusion over ownership, +lifetime, mutability, and similar issues, and no need to specify them in the +contract. It also prevents non-local interactions between the client and the +implementation, which makes them easier to understand, maintain, and optimize by +the compiler. Further, such objects can be used with generic APIs that +require pass-by-value, such as most containers, and they allow for additional +flexibility in e.g., type composition.
+ +Copy/move constructors and assignment operators are usually
+easier to define correctly than alternatives
+like Clone()
, CopyFrom()
or Swap()
,
+because they can be generated by the compiler, either implicitly or
+with = default
. They are concise, and ensure
+that all data members are copied. Copy and move
+constructors are also generally more efficient, because they don't
+require heap allocation or separate initialization and assignment
+steps, and they're eligible for optimizations such as
+
+
+copy elision.
Move operations allow the implicit and efficient transfer of +resources out of rvalue objects. This allows a plainer coding style +in some cases.
+Some types do not need to be copyable, and providing copy
+operations for such types can be confusing, nonsensical, or outright
+incorrect. Types representing singleton objects (Registerer
),
+objects tied to a specific scope (Cleanup
), or closely coupled to
+object identity (Mutex
) cannot be copied meaningfully.
+Copy operations for base class types that are to be used
+polymorphically are hazardous, because use of them can lead to
+object slicing.
+Defaulted or carelessly-implemented copy operations can be incorrect, and the
+resulting bugs can be confusing and difficult to diagnose.
Copy constructors are invoked implicitly, which makes the +invocation easy to miss. This may cause confusion for programmers used to +languages where pass-by-reference is conventional or mandatory. It may also +encourage excessive copying, which can cause performance problems.
+Provide the copy and move operations if their meaning is clear to a casual +user and the copying/moving does not incur unexpected costs. If you define a +copy or move constructor, define the corresponding assignment operator, and +vice-versa. If your type is copyable, do not define move operations unless they +are significantly more efficient than the corresponding copy operations. If your +type is not copyable, but the correctness of a move is obvious to users of the +type, you may make the type move-only by defining both of the move operations. +
+ +If your type provides copy operations, it is recommended that you design +your class so that the default implementation of those operations is correct. +Remember to review the correctness of any defaulted operations as you would any +other code, and to document that your class is copyable and/or cheaply movable +if that's an API guarantee.
+ +class Foo { + public: + Foo(Foo&& other) : field_(other.field) {} + // Bad, defines only move constructor, but not operator=. + + private: + Field field_; +}; ++ +
Due to the risk of slicing, avoid providing an assignment
+operator or public copy/move constructor for a class that's
+intended to be derived from (and avoid deriving from a class
+with such members). If your base class needs to be
+copyable, provide a public virtual Clone()
+method, and a protected copy constructor that derived classes
+can use to implement it.
If you do not want to support copy/move operations on your type,
+explicitly disable them using = delete
in
+the public:
section:
// MyClass is neither copyable nor movable. +MyClass(const MyClass&) = delete; +MyClass& operator=(const MyClass&) = delete; ++ + + +
Structs vs. Classes
+ +Use a struct
only for passive objects that
+ carry data; everything else is a class
.
The struct
and class
+keywords behave almost identically in C++. We add our own
+semantic meanings to each keyword, so you should use the
+appropriate keyword for the data-type you're
+defining.
structs
should be used for passive
+objects that carry data, and may have associated
+constants, but lack any functionality other than
+access/setting the data members. The accessing/setting of
+fields is done by directly accessing the fields rather
+than through method invocations. Methods should not
+provide behavior but should only be used to set up the
+data members, e.g., constructor, destructor,
+Initialize()
, Reset()
,
+Validate()
.
If more functionality is required, a
+class
is more appropriate. If in doubt, make
+it a class
.
For consistency with STL, you can use
+struct
instead of class
for
+functors and traits.
Note that member variables in structs and classes have +different naming rules.
+ +Inheritance
+ +Composition is often more appropriate than inheritance.
+When using inheritance, make it public
.
When a sub-class +inherits from a base class, it includes the definitions +of all the data and operations that the parent base class +defines. In practice, inheritance is used in two major +ways in C++: implementation inheritance, in which actual +code is inherited by the child, and +interface inheritance, in which +only method names are inherited.
+Implementation inheritance reduces code size by re-using +the base class code as it specializes an existing type. +Because inheritance is a compile-time declaration, you +and the compiler can understand the operation and detect +errors. Interface inheritance can be used to +programmatically enforce that a class expose a particular +API. Again, the compiler can detect errors, in this case, +when a class does not define a necessary method of the +API.
+For implementation inheritance, because the code +implementing a sub-class is spread between the base and +the sub-class, it can be more difficult to understand an +implementation. The sub-class cannot override functions +that are not virtual, so the sub-class cannot change +implementation. The base class may also define some data +members, so that specifies physical layout of the base +class.
+All inheritance should be public
. If you
+want to do private inheritance, you should be including
+an instance of the base class as a member instead.
Do not overuse implementation inheritance. Composition
+is often more appropriate. Try to restrict use of
+inheritance to the "is-a" case: Bar
+subclasses Foo
if it can reasonably be said
+that Bar
"is a kind of"
+Foo
.
Make your destructor virtual
if
+necessary. If your class has virtual methods, its
+destructor should be virtual.
Limit the use of protected
to those
+member functions that might need to be accessed from
+subclasses. Note that data
+members should be private.
Explicitly annotate overrides of virtual functions
+or virtual destructors with an override
+or (less frequently) final
specifier.
+Older (pre-C++11) code will use the
+virtual
keyword as an inferior
+alternative annotation. For clarity, use exactly one of
+override
, final
, or
+virtual
when declaring an override.
+Rationale: A function or destructor marked
+override
or final
that is
+not an override of a base class virtual function will
+not compile, and this helps catch common errors. The
+specifiers serve as documentation; if no specifier is
+present, the reader has to check all ancestors of the
+class in question to determine if the function or
+destructor is virtual or not.
Multiple Inheritance
+ +Only very rarely is multiple implementation inheritance
+actually useful. We allow multiple inheritance only when at
+most one of the base classes has an implementation; all
+other base classes must be pure
+interface classes tagged with the
+Interface
suffix.
Multiple inheritance allows a sub-class to have more than +one base class. We distinguish between base classes that are +pure interfaces and those that have an +implementation.
+Multiple implementation inheritance may let you re-use +even more code than single inheritance (see Inheritance).
+Only very rarely is multiple implementation +inheritance actually useful. When multiple implementation +inheritance seems like the solution, you can usually find +a different, more explicit, and cleaner solution.
+ Multiple inheritance is allowed only when all
+superclasses, with the possible exception of the first one,
+are pure interfaces. In order to
+ensure that they remain pure interfaces, they must end with
+the Interface
suffix.
There is an exception to +this rule on Windows.
+Interfaces
+ +Classes that satisfy certain conditions are allowed, but
+not required, to end with an Interface
suffix.
A class is a pure interface if it meets the following +requirements:
+ +-
+
- It has only public pure virtual ("
= + 0
") methods and static methods (but see below + for destructor).
+
+ - It may not have non-static data members. + +
- It need not have any constructors defined. If a + constructor is provided, it must take no arguments and + it must be protected. + +
- If it is a subclass, it may only be derived from
+ classes that satisfy these conditions and are tagged
+ with the
Interface
suffix.
+
An interface class can never be directly instantiated +because of the pure virtual method(s) it declares. To +make sure all implementations of the interface can be +destroyed correctly, the interface must also declare a +virtual destructor (in an exception to the first rule, +this should not be pure). See Stroustrup, The C++ +Programming Language, 3rd edition, section 12.4 +for details.
+Tagging a class with the Interface
suffix
+lets others know that they must not add implemented
+methods or non static data members. This is particularly
+important in the case of multiple inheritance.
+Additionally, the interface concept is already
+well-understood by Java programmers.
The Interface
suffix lengthens the class
+name, which can make it harder to read and understand.
+Also, the interface property may be considered an
+implementation detail that shouldn't be exposed to
+clients.
A class may end
+with Interface
only if it meets the above
+requirements. We do not require the converse, however:
+classes that meet the above requirements are not required
+to end with Interface
.
Operator Overloading
+ +Overload operators judiciously. Do not create user-defined literals.
+C++ permits user code to
+declare
+overloaded versions of the built-in operators using the
+operator
keyword, so long as one of the parameters
+is a user-defined type. The operator
keyword also
+permits user code to define new kinds of literals using
+operator""
, and to define type-conversion functions
+such as operator bool()
.
Operator overloading can make code more concise and
+intuitive by enabling user-defined types to behave the same
+as built-in types. Overloaded operators are the idiomatic names
+for certain operations (e.g. ==
, <
,
+=
, and <<
), and adhering to
+those conventions can make user-defined types more readable
+and enable them to interoperate with libraries that expect
+those names.
User-defined literals are a very concise notation for +creating objects of user-defined types.
+-
+
- Providing a correct, consistent, and unsurprising + set of operator overloads requires some care, and failure + to do so can lead to confusion and bugs. + +
- Overuse of operators can lead to obfuscated code, + particularly if the overloaded operator's semantics + don't follow convention. + +
- The hazards of function overloading apply just as + much to operator overloading, if not more so. + +
- Operator overloads can fool our intuition into + thinking that expensive operations are cheap, built-in + operations. + +
- Finding the call sites for overloaded operators may + require a search tool that's aware of C++ syntax, rather + than e.g. grep. + +
- If you get the argument type of an overloaded operator
+ wrong, you may get a different overload rather than a
+ compiler error. For example,
foo < bar
+ may do one thing, while&foo < &bar
+ does something totally different.
+
+ - Certain operator overloads are inherently hazardous.
+ Overloading unary
&
can cause the same + code to have different meanings depending on whether + the overload declaration is visible. Overloads of +&&
,||
, and,
+ (comma) cannot match the evaluation-order semantics of the + built-in operators.
+
+ - Operators are often defined outside the class, + so there's a risk of different files introducing + different definitions of the same operator. If both + definitions are linked into the same binary, this results + in undefined behavior, which can manifest as subtle + run-time bugs. + +
- User-defined literals allow the creation of new + syntactic forms that are unfamiliar even to experienced C++ + programmers. +
Define overloaded operators only if their meaning is
+obvious, unsurprising, and consistent with the corresponding
+built-in operators. For example, use |
as a
+bitwise- 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 namespaces
+as the types they operate on. That way, the operators are available
+wherever the type is, minimizing the risk of multiple
+definitions. If possible, avoid defining operators as templates,
+because they must satisfy this rule for any possible template
+arguments. If you define an operator, also define
+any related operators that make sense, and make sure they
+are defined consistently. For example, if you overload
+<
, overload all the comparison operators,
+and make sure <
and >
never
+return true for the same arguments.
Prefer to define non-modifying binary operators as
+non-member functions. If a binary operator is defined as a
+class member, implicit conversions will apply to the
+right-hand argument, but not the left-hand one. It will
+confuse your users if a < b
compiles but
+b < a
doesn't.
Don't go out of your way to avoid defining operator
+overloads. For example, prefer to define ==
,
+=
, and <<
, rather than
+Equals()
, CopyFrom()
, and
+PrintTo()
. Conversely, don't define
+operator overloads just because other libraries expect
+them. For example, if your type doesn't have a natural
+ordering, but you want to store it in a std::set
,
+use a custom comparator rather than overloading
+<
.
Do not overload &&
, ||
,
+,
(comma), or unary &
. Do not overload
+operator""
, i.e. do not introduce user-defined
+literals.
Type conversion operators are covered in the section on
+implicit conversions.
+The =
operator is covered in the section on
+copy constructors. Overloading
+<<
for use with streams is covered in the
+section on streams. See also the rules on
+function overloading, which
+apply to operator overloading as well.
Access Control
+ + Make data members private
, unless they are
+static const
(and follow the
+naming convention for constants). For technical
+reasons, we allow data members of a test fixture class to
+be protected
when using
+
+
+Google
+Test).
Declaration Order
+ +Group similar declarations together, placing public parts +earlier.
+A class definition should usually start with a
+public:
section, followed by
+protected:
, then private:
. Omit
+sections that would be empty.
Within each section, generally prefer grouping similar
+kinds of declarations together, and generally prefer the
+following order: types (including typedef
,
+using
, and nested structs and classes),
+constants, factory functions, constructors, assignment
+operators, destructor, all other methods, data members.
Do not put large method definitions inline in the +class definition. Usually, only trivial or +performance-critical, and very short, methods may be +defined inline. See Inline +Functions for more details.
+ +Functions
+ +Parameter Ordering
+ +When defining a function, parameter order is: inputs, then +outputs.
+Parameters to C/C++ functions are either input to the
+function, output from the function, or both. Input
+parameters are usually values or const
+references, while output and input/output parameters will
+be pointers to non-const
. When ordering
+function parameters, put all input-only parameters before
+any output parameters. In particular, do not add new
+parameters to the end of the function just because they
+are new; place new input-only parameters before the
+output parameters.
This is not a hard-and-fast rule. Parameters that are +both input and output (often classes/structs) muddy the +waters, and, as always, consistency with related +functions may require you to bend the rule.
+ +Write Short Functions
+ +Prefer small and focused functions.
+We recognize that long functions are sometimes +appropriate, so no hard limit is placed on functions +length. If a function exceeds about 40 lines, think about +whether it can be broken up without harming the structure +of the program.
+ +Even if your long function works perfectly now, +someone modifying it in a few months may add new +behavior. This could result in bugs that are hard to +find. Keeping your functions short and simple makes it +easier for other people to read and modify your code.
+ +You could find long and complicated functions when +working with +some code. Do not be +intimidated by modifying existing code: if working with +such a function proves to be difficult, you find that +errors are hard to debug, or you want to use a piece of +it in several different contexts, consider breaking up +the function into smaller and more manageable pieces.
+ +Reference Arguments
+ +All parameters passed by reference must be labeled
+const
.
In C, if a
+function needs to modify a variable, the parameter must
+use a pointer, eg int foo(int *pval)
. In
+C++, the function can alternatively declare a reference
+parameter: int foo(int &val)
.
Defining a parameter as reference avoids ugly code like
+(*pval)++
. Necessary for some applications
+like copy constructors. Makes it clear, unlike with
+pointers, that a null pointer is not a possible
+value.
References can be confusing, as they have value syntax +but pointer semantics.
+Within function parameter lists all references must be
+const
:
void Foo(const string &in, string *out); ++ +
In fact it is a very strong convention in Google code
+that input arguments are values or const
+references while output arguments are pointers. Input
+parameters may be const
pointers, but we
+never allow non-const
reference parameters
+except when required by convention, e.g.,
+swap()
.
However, there are some instances where using
+const T*
is preferable to const
+T&
for input parameters. For example:
-
+
- You want to pass in a null pointer. + +
- The function saves a pointer or reference to the + input. +
Remember that most of the time input
+parameters are going to be specified as const
+T&
. Using const T*
instead
+communicates to the reader that the input is somehow
+treated differently. So if you choose const
+T*
rather than const T&
, do so
+for a concrete reason; otherwise it will likely confuse
+readers by making them look for an explanation that
+doesn't exist.
Function Overloading
+ +Use overloaded functions (including constructors) only if a +reader looking at a call site can get a good idea of what +is happening without having to first figure out exactly +which overload is being called.
+You may write a function that takes a const
+string&
and overload it with another that
+takes const char*
.
class MyClass { + public: + void Analyze(const string &text); + void Analyze(const char *text, size_t textlen); +}; ++
Overloading can make code more intuitive by allowing an +identically-named function to take different arguments. +It may be necessary for templatized code, and it can be +convenient for Visitors.
+If a function is overloaded by the argument types alone, +a reader may have to understand C++'s complex matching +rules in order to tell what's going on. Also many people +are confused by the semantics of inheritance if a derived +class overrides only some of the variants of a +function.
+If you want to overload a function, consider qualifying
+the name with some information about the arguments, e.g.,
+AppendString()
, AppendInt()
+rather than just Append()
. If you are
+overloading a function to support variable number of
+arguments of the same type, consider making it take a
+std::vector
so that the user can use an
+initializer list
+ to specify the arguments.
Default Arguments
+ +Default arguments are allowed on non-virtual functions +when the default is guaranteed to always have the same +value. Follow the same restrictions as for function overloading, and +prefer overloaded functions if the readability gained with +default arguments doesn't outweigh the downsides below.
+Often you have a function that uses default values, but +occasionally you want to override the defaults. Default +parameters allow an easy way to do this without having to +define many functions for the rare exceptions. Compared +to overloading the function, default arguments have a +cleaner syntax, with less boilerplate and a clearer +distinction between 'required' and 'optional' +arguments.
+Defaulted arguments are another way to achieve the +semantics of overloaded functions, so all the reasons not to overload +functions apply.
+ +The defaults for arguments in a virtual function call are +determined by the static type of the target object, and +there's no guarantee that all overrides of a given function +declare the same defaults.
+ +Default parameters are re-evaluated at each call site, +which can bloat the generated code. Readers may also expect +the default's value to be fixed at the declaration instead +of varying at each call.
+ +Function pointers are confusing in the presence of +default arguments, since the function signature often +doesn't match the call signature. Adding +function overloads avoids these problems.
+Default arguments are banned on virtual functions, where
+they don't work properly, and in cases where the specified
+default might not evaluate to the same value depending on
+when it was evaluated. (For example, don't write void
+f(int n = counter++);
.)
In some other cases, default arguments can improve the +readability of their function declarations enough to +overcome the downsides above, so they are allowed. When in +doubt, 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 new form, introduced in C++11, uses the auto
+ 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 like int
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 a lambda 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 <class T, class U> auto add(T t, U u) -> decltype(t + u);+ versus +
template <class T, class 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 like 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 is + discouraged in most cases.
+ +Google-Specific Magic
+ + + +There are various tricks and utilities that +we use to make C++ code more robust, and various ways we use +C++ that may differ from what you see elsewhere.
+ + + +Ownership and Smart Pointers
+ +Prefer to have single, fixed owners for dynamically +allocated objects. Prefer to transfer ownership with smart +pointers.
+"Ownership" is a bookkeeping technique for managing +dynamically allocated memory (and other resources). The +owner of a dynamically allocated object is an object or +function that is responsible for ensuring that it is +deleted when no longer needed. Ownership can sometimes be +shared, in which case the last owner is typically +responsible for deleting it. Even when ownership is not +shared, it can be transferred from one piece of code to +another.
+ +"Smart" pointers are classes that act like pointers,
+e.g. by overloading the *
and
+->
operators. Some smart pointer types
+can be used to automate ownership bookkeeping, to ensure
+these responsibilities are met.
+
+std::unique_ptr
is a smart pointer type
+introduced in C++11, which expresses exclusive ownership
+of a dynamically allocated object; the object is deleted
+when the std::unique_ptr
goes out of scope.
+It cannot be copied, but can be moved to
+represent ownership transfer.
+
+std::shared_ptr
is a smart pointer type
+that expresses shared ownership of
+a dynamically allocated object. std::shared_ptr
s
+can be copied; ownership of the object is shared among
+all copies, and the object is deleted when the last
+std::shared_ptr
is destroyed.
-
+
- It's virtually impossible to manage dynamically + allocated memory without some sort of ownership + logic. + +
- Transferring ownership of an object can be cheaper + than copying it (if copying it is even possible). + +
- Transferring ownership can be simpler than + 'borrowing' a pointer or reference, because it reduces + the need to coordinate the lifetime of the object + between the two users. + +
- Smart pointers can improve readability by making + ownership logic explicit, self-documenting, and + unambiguous. + +
- Smart pointers can eliminate manual ownership + bookkeeping, simplifying the code and ruling out large + classes of errors. + +
- For const objects, shared ownership can be a simple + and efficient alternative to deep copying. +
-
+
- Ownership must be represented and transferred via + pointers (whether smart or plain). Pointer semantics + are more complicated than value semantics, especially + in APIs: you have to worry not just about ownership, + but also aliasing, lifetime, and mutability, among + other issues. + +
- The performance costs of value semantics are often + overestimated, so the performance benefits of ownership + transfer might not justify the readability and + complexity costs. + +
- APIs that transfer ownership force their clients + into a single memory management model. + +
- Code using smart pointers is less explicit about + where the resource releases take place. + +
std::unique_ptr
expresses ownership + transfer using C++11's move semantics, which are + relatively new and may confuse some programmers.
+
+ - Shared ownership can be a tempting alternative to + careful ownership design, obfuscating the design of a + system. + +
- Shared ownership requires explicit bookkeeping at + run-time, which can be costly. + +
- In some cases (e.g. cyclic references), objects + with shared ownership may never be deleted. + +
- Smart pointers are not perfect substitutes for + plain pointers. +
If dynamic allocation is necessary, prefer to keep
+ownership with the code that allocated it. If other code
+needs access to the object, consider passing it a copy,
+or passing a pointer or reference without transferring
+ownership. Prefer to use std::unique_ptr
to
+make 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 ownership
+without a very good reason. One such reason is to avoid
+expensive copy operations, but you should only do this if
+the performance benefits are significant, and the
+underlying object is immutable (i.e.
+std::shared_ptr<const Foo>
). If you
+do use shared ownership, prefer to use
+std::shared_ptr
.
Never use std::auto_ptr
. Instead, use
+std::unique_ptr
.
cpplint
+ +Use cpplint.py
+to detect style errors.
cpplint.py
+is a tool that reads a source file and identifies many
+style errors. It is not perfect, and has both false
+positives and false negatives, but it is still a valuable
+tool. False positives can be ignored by putting //
+NOLINT
at the end of the line or
+// NOLINTNEXTLINE
in the previous line.
Some projects have instructions on
+how to run cpplint.py
from their project
+tools. If the project you are contributing to does not,
+you can download
+
+cpplint.py
separately.
Other C++ Features
+ +Rvalue References
+ +Use rvalue references only to define move constructors and move assignment +operators, or for perfect forwarding. +
+ Rvalue references
+are a type of reference that can only bind to temporary
+objects. The syntax is similar to traditional reference
+syntax. For example, void f(string&&
+s);
declares a function whose argument is an
+rvalue reference to a string.
-
+
- Defining a move constructor (a constructor taking
+ an rvalue reference to the class type) makes it
+ possible to move a value instead of copying it. If
+
v1
is astd::vector<string>
, + for example, thenauto v2(std::move(v1))
+ will probably just result in some simple pointer + manipulation instead of copying a large amount of data. + In some cases this can result in a major performance + improvement.
+
+ - Rvalue references make it possible to write a + generic function wrapper that forwards its arguments to + another function, and works whether or not its + arguments are temporary objects. (This is sometimes called + "perfect forwarding".) + +
- Rvalue references make it possible to implement + types that are movable but not copyable, which can be + useful for types that have no sensible definition of + copying but where you might still want to pass them as + function arguments, put them in containers, etc. + +
std::move
is necessary to make + effective use of some standard-library types, such as +std::unique_ptr
.
+
-
+
- Rvalue references are a relatively new feature + (introduced as part of C++11), and not yet widely + understood. Rules like reference collapsing, and + automatic synthesis of move constructors, are + complicated. +
Use rvalue references only to define move constructors and move assignment
+ operators (as described in Copyable and
+ Movable Types) and, in conjunction with std::forward
,
+to support perfect forwarding. You may use std::move
to express
+moving a value from one object to another rather than copying it.
Friends
+ +We allow use of friend
classes and functions,
+within reason.
Friends should usually be defined in the same file so
+that the reader does not have to look in another file to
+find uses of the private members of a class. A common use
+of friend
is to have a
+FooBuilder
class be a friend of
+Foo
so that it can construct the inner state
+of Foo
correctly, without exposing this
+state to the world. In some cases it may be useful to
+make a unittest class a friend of the class it tests.
Friends extend, but do not break, the encapsulation +boundary of a class. In some cases this is better than +making a member public when you want to give only one +other class access to it. However, most classes should +interact with other classes solely through their public +members.
+ +Exceptions
+ +We do not use C++ exceptions.
+-
+
- Exceptions allow higher levels of an application to + decide how to handle "can't happen" failures in deeply + nested functions, without the obscuring and error-prone + bookkeeping of error codes. + + + +
- Exceptions are used by most other + modern languages. Using them in C++ would make it more + consistent with Python, Java, and the C++ that others + are familiar with. + +
- Some third-party C++ libraries use exceptions, and + turning them off internally makes it harder to + integrate with those libraries. + +
- Exceptions are the only way for a constructor to
+ fail. We can simulate this with a factory function or
+ an
Init()
method, but these require heap + allocation or a new "invalid" state, respectively.
+
+ - Exceptions are really handy in testing + frameworks. +
-
+
- When you add a
throw
statement to an + existing function, you must examine all of its + transitive callers. Either they must make at least the + basic exception safety guarantee, or they must never + catch the exception and be happy with the program + terminating as a result. For instance, if +f()
callsg()
calls +h()
, andh
throws an + exception thatf
catches,g
+ has to be careful or it may not clean up properly.
+
+ - More generally, exceptions make the control flow of + programs difficult to evaluate by looking at code: + functions may return in places you don't expect. This + causes maintainability and debugging difficulties. You + can minimize this cost via some rules on how and where + exceptions can be used, but at the cost of more that a + developer needs to know and understand. + +
- Exception safety requires both RAII and different + coding practices. Lots of supporting machinery is + needed to make writing correct exception-safe code + easy. Further, to avoid requiring readers to understand + the entire call graph, exception-safe code must isolate + logic that writes to persistent state into a "commit" + phase. This will have both benefits and costs (perhaps + where you're forced to obfuscate code to isolate the + commit). Allowing exceptions would force us to always + pay those costs even when they're not worth it. + +
- Turning on exceptions adds data to each binary + produced, increasing compile time (probably slightly) + and possibly increasing address space pressure. + + +
- The availability of exceptions may encourage + developers to throw them when they are not appropriate + or recover from them when it's not safe to do so. For + example, invalid user input should not cause exceptions + to be thrown. We would need to make the style guide + even longer to document these restrictions! +
On their face, the benefits of using exceptions +outweigh the costs, especially in new projects. However, +for existing code, the introduction of exceptions has +implications on all dependent code. If exceptions can be +propagated beyond a new project, it also becomes +problematic to integrate the new project into existing +exception-free code. Because most existing C++ code at +Google is not prepared to deal with exceptions, it is +comparatively difficult to adopt new code that generates +exceptions.
+ +Given that Google's existing code is not +exception-tolerant, the costs of using exceptions are +somewhat greater than the costs in a new project. The +conversion process would be slow and error-prone. We +don't believe that the available alternatives to +exceptions, such as error codes and assertions, introduce +a significant burden.
+ +Our advice against using exceptions is not predicated +on philosophical or moral grounds, but practical ones. + Because we'd like to use our open-source +projects at Google and it's difficult to do so if those +projects use exceptions, we need to advise against +exceptions in Google open-source projects as well. +Things would probably be different if we had to do it all +over again from scratch.
+ +This prohibition also applies to the exception-related
+features added in C++11, such as noexcept
,
+std::exception_ptr
, and
+std::nested_exception
.
There is an exception to +this rule (no pun intended) for Windows code.
+Run-Time Type +Information (RTTI)
+ +Avoid using Run Time Type Information (RTTI).
+ RTTI allows a
+programmer to query the C++ class of an object at run
+time. This is done by use of typeid
or
+dynamic_cast
.
Querying the type of an object at run-time frequently +means a design problem. Needing to know the type of an +object at runtime is often an indication that the design +of your class hierarchy is flawed.
+ +Undisciplined use of RTTI makes code hard to maintain. +It can lead to type-based decision trees or switch +statements scattered throughout the code, all of which +must be examined when making further changes.
+The standard alternatives to RTTI (described below) +require modification or redesign of the class hierarchy +in question. Sometimes such modifications are infeasible +or undesirable, particularly in widely-used or mature +code.
+ +RTTI can be useful in some unit tests. For example, it +is useful in tests of factory classes where the test has +to verify that a newly created object has the expected +dynamic type. It is also useful in managing the +relationship between objects and their mocks.
+ +RTTI is useful when considering multiple abstract +objects. Consider
+ +bool Base::Equal(Base* other) = 0; +bool Derived::Equal(Base* other) { + Derived* that = dynamic_cast<Derived*>(other); + if (that == NULL) + return false; + ... +} ++
RTTI has legitimate uses but is prone to abuse, so you +must be careful when using it. You may use it freely in +unittests, but avoid it when possible in other code. In +particular, think twice before using RTTI in new code. If +you find yourself needing to write code that behaves +differently based on the class of an object, consider one +of the following alternatives to querying the type:
+ +-
+
- Virtual methods are the preferred way of executing + different code paths depending on a specific subclass + type. This puts the work within the object itself. + +
- If the work belongs outside the object and instead + in some processing code, consider a double-dispatch + solution, such as the Visitor design pattern. This + allows a facility outside the object itself to + determine the type of class using the built-in type + system. +
When the logic of a program guarantees that a given
+instance of a base class is in fact an instance of a
+particular derived class, then a
+dynamic_cast
may be used freely on the
+object. Usually one
+can use a static_cast
as an alternative in
+such situations.
Decision trees based on type are a strong indication +that 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 additional +subclasses are added to the class hierarchy. Moreover, +when properties of a subclass change, it is difficult to +find and modify all the affected code segments.
+ +Do not hand-implement an RTTI-like workaround. The +arguments against RTTI apply just as much to workarounds +like class hierarchies with type tags. Moreover, +workarounds disguise your true intent.
+Casting
+ +Use C++-style casts
+like static_cast<float>(double_value)
, or brace
+initialization for conversion of arithmetic types like
+int64 y = int64{1} << 42
. Do not use
+cast formats like
+int y = (int)x
or int y = int(x)
(but the latter
+is okay when invoking a constructor of a class type).
C++ introduced a +different cast system from C that distinguishes the types +of cast operations.
+The problem with C casts is the ambiguity of the operation;
+sometimes you are doing a conversion
+(e.g., (int)3.5
) and sometimes you are doing
+a cast (e.g., (int)"hello"
). Brace
+initialization and C++ casts can often help avoid this
+ambiguity. Additionally, C++ casts are more visible when searching for
+them.
The C++-style cast syntax is verbose and cumbersome.
+Do not use C-style casts. Instead, use these C++-style casts when +explicit type conversion is necessary.
+ +-
+
- Use brace initialization to convert arithmetic types
+ (e.g.
int64{x}
). This is the safest approach because code + will not compile if conversion can result in information loss. The + syntax is also concise.
+
+
+
+ - Use
static_cast
as the equivalent of a C-style cast + that does value conversion, when you need to + explicitly up-cast a pointer from a class to its superclass, or when + you need to explicitly cast a pointer from a superclass to a + subclass. In this last case, you must be sure your object is + actually an instance of the subclass.
+
+
+
+ - Use
const_cast
to remove the +const
qualifier (see const).
+
+ - Use
reinterpret_cast
to do unsafe + conversions of pointer types to and from integer and + other pointer types. Use this only if you know what you + are doing and you understand the aliasing issues. +
+
+
+
See the
+RTTI section for guidance on the use of
+dynamic_cast
.
Streams
+ +Use streams where appropriate, and stick to "simple" +usages.
+Streams are the standard I/O abstraction in C++, as
+exemplified by the standard header <iostream>
.
+They are widely used in Google code, but only for debug logging
+and test diagnostics.
The <<
and >>
+stream operators provide an API for formatted I/O that
+is easily learned, portable, reusable, and extensible.
+printf
, by contrast, doesn't even support
+string
, to say nothing of user-defined types,
+and is very difficult to use portably.
+printf
also obliges you to choose among the
+numerous slightly different versions of that function,
+and navigate the dozens of conversion specifiers.
Streams provide first-class support for console I/O
+via std::cin
, std::cout
,
+std::cerr
, and std::clog
.
+The C APIs do as well, but are hampered by the need to
+manually buffer the input.
-
+
- Stream formatting can be configured by mutating the +state of the stream. Such mutations are persistent, so +the behavior of your code can be affected by the entire +previous history of the stream, unless you go out of your +way to restore it to a known state every time other code +might have touched it. User code can not only modify the +built-in state, it can add new state variables and behaviors +through a registration system. + +
- It is difficult to precisely control stream output, due +to the above issues, the way code and data are mixed in +streaming code, and the use of operator overloading (which +may select a different overload than you expect). + +
- The practice of building up output through chains
+of
<<
operators interferes with +internationalization, because it bakes word order into the +code, and streams' support for localization is +flawed.
+
+
+
+
+
+ - The streams API is subtle and complex, so programmers must +develop experience with it in order to use it effectively. +However, streams were historically banned in Google code (except +for logging and diagnostics), so Google engineers tend not to +have that experience. Consequently, streams-based code is likely +to be less readable and maintainable by Googlers than code based +on more familiar abstractions. + +
- Resolving the many overloads of
<<
is +extremely costly for the compiler. When used pervasively in a +large code base, it can consume as much as 20% of the parsing +and semantic analysis time.
+
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 than +end-users. Be consistent with the code around you, and with the +codebase as a whole; if there's an established tool for +your problem, use that tool instead.
+ +Avoid using streams for I/O that faces external users or +handles untrusted data. Instead, find and use the appropriate +templating libraries to handle issues like internationalization, +localization, and security hardening.
+ +If you do use streams, avoid the stateful parts of the
+streams API (other than error state), such as imbue()
,
+xalloc()
, and register_callback()
.
+Use explicit formatting functions rather than
+stream manipulators or formatting flags to control formatting
+details such as number base, precision, or padding.
Overload <<
as a streaming operator
+for your type only if your type represents a value, and
+<<
writes out a human-readable string
+representation of that value. Avoid exposing implementation
+details in the output of <<
; if you need to print
+object internals for debugging, use named functions instead
+(a method named DebugString()
is the most common
+convention).
Preincrement and Predecrement
+ +Use prefix form (++i
) of the increment and
+decrement operators with iterators and other template
+objects.
When a variable
+is incremented (++i
or i++
) or
+decremented (--i
or i--
) and
+the value of the expression is not used, one must decide
+whether to preincrement (decrement) or postincrement
+(decrement).
When the return value is ignored, the "pre" form
+(++i
) is never less efficient than the
+"post" form (i++
), and is often more
+efficient. This is because post-increment (or decrement)
+requires a copy of i
to be made, which is
+the value of the expression. If i
is an
+iterator or other non-scalar type, copying i
+could be expensive. Since the two types of increment
+behave the same when the value is ignored, why not just
+always pre-increment?
The tradition developed, in C, of using post-increment
+when the expression value is not used, especially in
+for
loops. Some find post-increment easier
+to read, since the "subject" (i
) precedes
+the "verb" (++
), just like in English.
For simple scalar +(non-object) values there is no reason to prefer one form +and we allow either. For iterators and other template +types, use pre-increment.
+Use of const
+ +Use const
whenever it makes sense. With C++11,
+constexpr
is a better choice for some uses of
+const.
Declared variables and parameters can be preceded
+by the keyword const
to indicate the variables
+are not changed (e.g., const int foo
). Class
+functions can have the const
qualifier to
+indicate the function does not change the state of the
+class member variables (e.g., class Foo { int
+Bar(char c) const; };
).
Easier for people to understand how variables are being +used. Allows the compiler to do better type checking, +and, conceivably, generate better code. Helps people +convince themselves of program correctness because they +know the functions they call are limited in how they can +modify your variables. Helps people know what functions +are safe to use without locks in multi-threaded +programs.
+const
is viral: if you pass a
+const
variable to a function, that function
+must have const
in its prototype (or the
+variable will need a const_cast
). This can
+be a particular problem when calling library
+functions.
const
variables, data members, methods
+and arguments add a level of compile-time type checking;
+it is better to detect errors as soon as possible.
+Therefore we strongly recommend that you use
+const
whenever it makes sense to do so:
-
+
- If a function guarantees that it will not modify an argument
+ passed by reference or by pointer, the corresponding function parameter
+ should be a reference-to-const (
const T&
) or + pointer-to-const (const T*
), respectively.
+
+ - Declare methods to be
const
whenever + possible. Accessors should almost always be +const
. Other methods should be const if + they do not modify any data members, do not call any + non-const
methods, and do not return a + non-const
pointer or + non-const
reference to a data member.
+
+ - Consider making data members
const
+ whenever they do not need to be modified after + construction.
+
The mutable
keyword is allowed but is
+unsafe when used with threads, so thread safety should be
+carefully considered first.
Where to put the const
+ +Some people favor the form int const *foo
+to const int* foo
. They argue that this is
+more readable because it's more consistent: it keeps the
+rule that const
always follows the object
+it's describing. However, this consistency argument
+doesn't apply in codebases with few deeply-nested pointer
+expressions since most const
expressions
+have only one const
, and it applies to the
+underlying value. In such cases, there's no consistency
+to maintain. Putting the const
first is
+arguably more readable, since it follows English in
+putting the "adjective" (const
) before the
+"noun" (int
).
That said, while we encourage putting
+const
first, we do not require it. But be
+consistent with the code around you!
Use of constexpr
+ +In C++11, use constexpr
to define true
+constants or to ensure constant initialization.
Some variables can be declared constexpr
+to indicate the variables are true constants, i.e. fixed at
+compilation/link time. Some functions and constructors
+can be declared constexpr
which enables them
+to be used in defining a constexpr
+variable.
Use of constexpr
enables definition of
+constants with floating-point expressions rather than
+just literals; definition of constants of user-defined
+types; and definition of constants with function
+calls.
Prematurely marking something as constexpr may cause +migration problems if later on it has to be downgraded. +Current restrictions on what is allowed in constexpr +functions and constructors may invite obscure workarounds +in these definitions.
+constexpr
definitions enable a more
+robust specification of the constant parts of an
+interface. Use constexpr
to specify true
+constants and the functions that support their
+definitions. Avoid complexifying function definitions to
+enable their use with constexpr
. Do not use
+constexpr
to force inlining.
Integer Types
+ +Of the built-in C++ integer types, the only one used
+ is
+int
. If a program needs a variable of a
+different size, use
+a precise-width integer type from
+<stdint.h>
, such as
+int16_t
. If your variable represents a
+value that could ever be greater than or equal to 2^31
+(2GiB), use a 64-bit type such as
+int64_t
.
+Keep in mind that even if your value won't ever be too large
+for an int
, it may be used in intermediate
+calculations which may require a larger type. When in doubt,
+choose a larger type.
C++ does not specify the sizes of its integer types.
+Typically people assume that short
is 16 bits,
+int
is 32 bits, long
is 32 bits
+and long long
is 64 bits.
Uniformity of declaration.
+The sizes of integral types in C++ can vary based on +compiler and architecture.
+
+<stdint.h>
defines types
+like int16_t
, uint32_t
,
+int64_t
, etc. You should always use
+those in preference to short
, unsigned
+long long
and the like, when you need a guarantee
+on the size of an integer. Of the C integer types, only
+int
should be used. When appropriate, you
+are welcome to use standard types like
+size_t
and ptrdiff_t
.
We use int
very often, for integers we
+know are not going to be too big, e.g., loop counters.
+Use plain old int
for such things. You
+should assume that an int
is
+
+at least 32 bits, but don't
+assume that it has more than 32 bits. If you need a 64-bit
+integer type, use
+int64_t
+or
+uint64_t
.
For integers we know can be "big",
+ use
+int64_t
.
+
You should not use the unsigned integer types such as
+uint32_t
, unless there is a valid
+reason such as representing a bit pattern rather than a
+number, or you need defined overflow modulo 2^N. In
+particular, do not use unsigned types to say a number
+will never be negative. Instead, use
+assertions for this.
If your code is a container that returns a size, be +sure to use a type that will accommodate any possible +usage of your container. When in doubt, use a larger type +rather than a smaller type.
+ +Use care when converting integer types. Integer +conversions and promotions can cause non-intuitive +behavior.
+On Unsigned Integers
+ +Some people, including some textbook authors, +recommend using unsigned types to represent numbers that +are never negative. This is intended as a form of +self-documentation. However, in C, the advantages of such +documentation are outweighed by the real bugs it can +introduce. Consider:
+ +for (unsigned int i = foo.Length()-1; i >= 0; --i) ... ++ +
This code will never terminate! Sometimes gcc will +notice this bug and warn you, but often it will not. +Equally bad bugs can occur when comparing signed and +unsigned variables. Basically, C's type-promotion scheme +causes unsigned types to behave differently than one +might expect.
+ +So, document that a variable is non-negative using +assertions. Don't use an unsigned +type.
+64-bit Portability
+ +Code should be 64-bit and 32-bit friendly. Bear in mind +problems of printing, comparisons, and structure alignment.
+-
+
-
+
+ +printf()
specifiers for some types + are not cleanly portable between 32-bit and 64-bit + systems. C99 defines some portable format specifiers. + Unfortunately, MSVC 7.1 does not understand some of + these specifiers and the standard is missing a few, + so we + have to define our own ugly versions in some cases + (in the style of the standard include file +inttypes.h
):++ +// printf macros for size_t, in the style of inttypes.h +#ifdef _LP64 +#define __PRIS_PREFIX "z" +#else +#define __PRIS_PREFIX +#endif + +// Use these macros after a % in a printf format string +// to get correct 32/64 bit behavior, like this: +// size_t size = records.size(); +// printf("%" PRIuS "\n", size); + +#define PRIdS __PRIS_PREFIX "d" +#define PRIxS __PRIS_PREFIX "x" +#define PRIuS __PRIS_PREFIX "u" +#define PRIXS __PRIS_PREFIX "X" +#define PRIoS __PRIS_PREFIX "o" +
++
+ ++ + +Type +DO NOT use +DO use +Notes ++ + + + + +void *
(or any pointer) +%lx
+%p
+ + + + + + +int64_t
+%qd
,%lld
+%" PRId64 "
+ + + + + + +uint64_t
+%qu
,%llu
, +%llx
+%" PRIu64 "
, +%" PRIx64 "
+ + + + +size_t
+%u
+%" PRIuS "
,%" PRIxS "
+ C99 specifies +%zu
+ + + + +ptrdiff_t
+%d
+%" PRIdS "
+ C99 specifies +%td
Note that the
+ + +PRI*
macros expand to + independent strings which are concatenated by the + compiler. Hence if you are using a non-constant + format string, you need to insert the value of the + macro into the format, rather than the name. Note also + that spaces are required around the macro identifier to + separate it from the string literal. It is + still possible, as usual, to include length + specifiers, etc., after the%
when using + thePRI*
macros. So, e.g. +printf("x = %30" PRIuS "\n", x)
would + expand on 32-bit Linux toprintf("x = %30" "u" + "\n", x)
, which the compiler will treat as +printf("x = %30u\n", x)
.
+
+ - Remember that
sizeof(void *)
!= +sizeof(int)
. Useintptr_t
if + you want a pointer-sized integer.
+
+ - You may need to be careful with structure
+ alignments, particularly for structures being stored on
+ disk. Any class/structure with a
+
int64_t
/uint64_t
+ member will by default end up being 8-byte aligned on a + 64-bit system. If you have such structures being shared + on disk between 32-bit and 64-bit code, you will need + to ensure that they are packed the same on both + architectures. + Most compilers offer a way to + alter structure alignment. For gcc, you can use +__attribute__((packed))
. MSVC offers +#pragma pack()
and +__declspec(align())
.
+
+ -
+
Use the
+ + +LL
orULL
+ suffixes as needed to create 64-bit constants. For + example:int64_t my_value = 0x123456789LL; +uint64_t my_mask = 3ULL << 48; +
+
+
Preprocessor Macros
+ +Avoid defining macros, especially in headers; prefer
+inline functions, enums, and const
variables.
+Name macros with a project-specific prefix. Do not use
+macros to define pieces of a C++ API.
Macros mean that the code you see is not the same as +the code the compiler sees. This can introduce unexpected +behavior, especially since macros have global scope.
+ +The problems introduced by macros are especially severe +when they are used to define pieces of a C++ API, +and still more so for public APIs. Every error message from +the compiler when developers incorrectly use that interface +now must explain how the macros formed the interface. +Refactoring and analysis tools have a dramatically harder +time updating the interface. As a consequence, we +specifically 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++ as
+they are in C. Instead of using a macro to inline
+performance-critical code, use an inline function.
+Instead of using a macro to store a constant, use a
+const
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, for
+the #define
guards to prevent double
+inclusion of header files). It makes testing much more
+difficult.
Macros can do things these other techniques cannot, +and you do see them in the codebase, especially in the +lower-level libraries. And some of their special features +(like stringifying, concatenation, and so forth) are not +available through the language proper. But before using a +macro, consider carefully whether there's a non-macro way +to achieve the same result. If you need to use a macro to +define an interface, contact +your project leads to request +a waiver of this rule.
+ +The following usage pattern will avoid many problems +with macros; if you use macros, follow it whenever +possible:
+ +-
+
- Don't define macros in a
.h
file.
+
+ #define
macros right before you use + them, and#undef
them right after.
+
+ - Do not just
#undef
an existing macro + before replacing it with your own; instead, pick a name + that's likely to be unique.
+
+ - Try not to use macros that expand to unbalanced C++ + constructs, or at least document that behavior + well. + +
- Prefer not using
##
to generate + function/class/variable names.
+
Exporting macros from headers (i.e. defining them in a header
+without #undef
ing them before the end of the header)
+is extremely strongly discouraged. If you do export a macro from a
+header, it must have a globally unique name. To achieve this, it
+must be named with a prefix consisting of your project's namespace
+name (but upper case).
0 and nullptr/NULL
+ +Use 0
for integers, 0.0
for
+reals, nullptr
(or NULL
) for
+pointers, and '\0'
for chars.
Use 0
for integers and 0.0
+for reals. This is not controversial.
For
+pointers (address values), there is a choice between
+0
, NULL
, and
+nullptr
. For projects that allow C++11
+features, use nullptr
. For C++03 projects,
+we prefer NULL
because it looks like a
+pointer. In fact, some C++ compilers provide special
+definitions of NULL
which enable them to
+give useful warnings, particularly in situations where
+sizeof(NULL)
is not equal to
+sizeof(0)
.
Use '\0'
for chars. This is the correct
+type and also makes code more readable.
sizeof
+ +Prefer sizeof(varname)
to
+sizeof(type)
.
Use sizeof(varname)
when you
+take the size of a particular variable.
+sizeof(varname)
will update
+appropriately if someone changes the variable type either
+now or later. You may use
+sizeof(type)
for code unrelated
+to any particular variable, such as code that manages an
+external or internal data format where a variable of an
+appropriate C++ type is not convenient.
Struct data; +memset(&data, 0, sizeof(data)); ++ +
memset(&data, 0, sizeof(Struct)); ++ +
if (raw_size < sizeof(int)) { + LOG(ERROR) << "compressed record not big enough for count: " << raw_size; + return false; +} ++ +
auto
+ +Use auto
to avoid type names that are noisy, obvious,
+or unimportant - cases where the type doesn't aid in clarity for the
+reader. Continue to use manifest type declarations when it helps
+readability.
+
-
+
- C++ type names can be long and cumbersome, especially when they +involve templates or namespaces. +
- When a C++ type name is repeated within a single declaration or a +small code region, the repetition may not be aiding readability. +
- It is sometimes safer to let the type be specified by the type of +the initialization expression, since that avoids the possibility of +unintended copies or type conversions. +
Sometimes code is clearer when types are manifest, +especially when a variable's initialization depends on +things that were declared far away. 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
+of y
isn't very well known, or if y
was
+declared many lines earlier.
Programmers have to understand the difference between
+auto
and const auto&
or
+they'll get copies when they didn't mean to.
If an auto
variable is used as part of an
+interface, e.g. as a constant in a header, then a
+programmer might change its type while only intending to
+change its value, leading to a more radical API change
+than intended.
auto
is permitted when it increases readability,
+particularly as described below. Never initialize an auto
-typed
+variable with a braced initializer list.
Specific cases where auto
is allowed or encouraged:
+
-
+
- (Encouraged) For iterators and other long/cluttery type names, particularly
+when the type is clear from context (calls
+to
find
,begin
, orend
for +instance).
+ - (Allowed) When the type is clear from local context (in the same expression
+or within a few lines). Initialization of a pointer or smart pointer
+with calls
+to
new
+commonly falls into this category, as does use ofauto
in +a range-based loop over a container whose type is spelled out +nearby.
+ - (Allowed) When the type doesn't matter because it isn't being used for +anything other than equality comparison. +
- (Encouraged) When iterating over a map with a range-based loop
+(because it is often assumed that the correct type
+is
std::pair<KeyType, ValueType>
whereas it is actually +std::pair<const KeyType, ValueType>
). This is +particularly well paired with localkey
+andvalue
aliases for.first
+and.second
(often const-ref). +for (const auto& item : some_map) { + const KeyType& key = item.first; + const ValType& value = item.second; + // The rest of the loop can now just refer to key and value, + // a reader can see the types in question, and we've avoided + // the too-common case of extra copies in this iteration. +} +
+
+
Braced Initializer List
+ +You may use braced initializer lists.
+In C++03, aggregate types (arrays and structs with no +constructor) could be initialized with braced initializer lists.
+ +struct Point { int x; int y; }; +Point p = {1, 2}; ++ +
In C++11, this syntax was generalized, and any object type can now +be created with a braced initializer list, known as a +braced-init-list in the C++ grammar. Here are a few examples +of its use.
+ +// Vector takes a braced-init-list of elements. +std::vector<string> v{"foo", "bar"}; + +// Basically the same, ignoring some small technicalities. +// You may choose to use either form. +std::vector<string> v = {"foo", "bar"}; + +// Usable with 'new' expressions. +auto p = new vector<string>{"foo", "bar"}; + +// A map can take a list of pairs. Nested braced-init-lists work. +std::map<int, string> m = {{1, "one"}, {2, "2"}}; + +// A braced-init-list can be implicitly converted to a return type. +std::vector<int> test_function() { return {1, 2, 3}; } + +// Iterate over a braced-init-list. +for (int i : {-1, -2, -3}) {} + +// Call a function using a braced-init-list. +void TestFunction2(std::vector<int> v) {} +TestFunction2({1, 2, 3}); ++ +
A user-defined type can also define a constructor and/or assignment operator
+that take std::initializer_list<T>
, which is automatically
+created from braced-init-list:
class MyType { + public: + // std::initializer_list references the underlying init list. + // It should be passed by value. + MyType(std::initializer_list<int> init_list) { + for (int i : init_list) append(i); + } + MyType& operator=(std::initializer_list<int> init_list) { + clear(); + for (int i : init_list) append(i); + } +}; +MyType m{2, 3, 5, 7}; ++ +
Finally, brace initialization can also call ordinary
+constructors of data types, even if they do not have
+std::initializer_list<T>
constructors.
double d{1.23}; +// Calls ordinary constructor as long as MyOtherType has no +// std::initializer_list constructor. +class MyOtherType { + public: + explicit MyOtherType(string); + MyOtherType(int, string); +}; +MyOtherType m = {1, "b"}; +// If the constructor is explicit, you can't use the "= {}" form. +MyOtherType m{"b"}; ++ +
Never assign a braced-init-list to an auto +local variable. In the single element case, what this +means can be confusing.
+ +auto d = {1.23}; // d is a std::initializer_list<double> ++ +
auto d = double{1.23}; // Good -- d is a double, not a std::initializer_list. ++ +
See Braced_Initializer_List_Format for formatting.
+ +Lambda expressions
+ +Use lambda expressions where appropriate. Prefer explicit captures +when the lambda will escape the current scope.
+Lambda expressions are a concise way of creating anonymous +function objects. They're often useful when passing +functions 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 either +explicitly by name, or implicitly using a default capture. Explicit captures +require each variable to be listed, as +either 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 the +lambda body, including
this
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]; +}); ++ +
Lambdas were introduced in C++11 along with a set of utilities
+for working with function objects, such as the polymorphic
+wrapper std::function
.
+
-
+
- Lambdas are much more concise than other ways of + defining function objects to be passed to STL + algorithms, which can be a readability + improvement. + +
- Appropriate use of default captures can remove + redundancy and highlight important exceptions from + the default. + +
- Lambdas,
std::function
, and +std::bind
can be used in combination as a + general purpose callback mechanism; they make it easy + to write functions that take bound functions as + arguments.
+
-
+
- Variable capture in lambdas can be a source of dangling-pointer + bugs, particularly if a lambda escapes the current scope. + +
- Default captures by value can be misleading because they do not prevent + dangling-pointer bugs. Capturing a pointer by value doesn't cause a deep + copy, so it often has the same lifetime issues as capture by reference. + This is especially confusing when capturing 'this' by value, since the use + of 'this' is often implicit. + +
- It's possible for use of lambdas to get out of + hand; very long nested anonymous functions can make + code harder to understand. + +
-
+
- Use lambda expressions where appropriate, with formatting as +described below. +
- Prefer explicit captures if the lambda may escape the current scope.
+For example, instead of:
+
{ + Foo foo; + ... + executor->Schedule([&] { Frobnicate(foo); }) + ... +} +// BAD! The fact that the lambda makes use of a reference to `foo` and +// possibly `this` (if `Frobnicate` is a member function) may not be +// apparent on a cursory inspection. If the lambda is invoked after +// the function returns, that would be bad, because both `foo` +// and the enclosing object could have been destroyed. +
+prefer to write: +{ + Foo foo; + ... + executor->Schedule([&foo] { Frobnicate(foo); }) + ... +} +// BETTER - The compile will fail if `Frobnicate` is a member +// function, and it's clearer that `foo` is dangerously captured by +// reference. +
+
+ - Use default capture by reference ([&]) only when the +lifetime of the lambda is obviously shorter than any potential +captures. + +
- Use default capture by value ([=]) only as a means of binding a +few variables for a short lambda, where the set of captured +variables is obvious at a glance. Prefer not to write long or +complex lambdas with default capture by value. + +
- Keep unnamed lambdas short. If a lambda body is more than +maybe five lines long, prefer to give the lambda a name, or to +use a named function instead of a lambda. +
- Specify the return type of the lambda explicitly if that will
+make it more obvious to readers, as with
+
auto
.
+
+
Template metaprogramming
+Avoid complicated template programming.
+Template metaprogramming refers to a family of techniques that +exploit the fact that the C++ template instantiation mechanism is +Turing complete and can be used to perform arbitrary compile-time +computation in the type domain.
+Template metaprogramming allows extremely flexible interfaces that
+are type safe and high performance. Facilities like
+
+Google Test,
+std::tuple
, std::function
, and
+Boost.Spirit would be impossible without it.
The techniques used in template metaprogramming are often obscure +to anyone but language experts. Code that uses templates in +complicated ways is often unreadable, and is hard to debug or +maintain.
+ +Template metaprogramming often leads to extremely poor compiler +time error messages: even if an interface is simple, the complicated +implementation details become visible when the user does something +wrong.
+ +Template metaprogramming interferes with large scale refactoring by +making the job of refactoring tools harder. First, the template code +is expanded in multiple contexts, and it's hard to verify that the +transformation makes sense in all of them. Second, some refactoring +tools work with an AST that only represents the structure of the code +after template expansion. It can be difficult to automatically work +back to the original source construct that needs to be +rewritten.
+Template metaprogramming sometimes allows cleaner and easier-to-use +interfaces than would be possible without it, but it's also often a +temptation to be overly clever. It's best used in a small number of +low level components where the extra maintenance burden is spread out +over a large number of uses.
+ +Think twice before using template metaprogramming or other
+complicated template techniques; think about whether the average
+member of your team will be able to understand your code well enough
+to maintain it after you switch to another project, or whether a
+non-C++ programmer or someone casually browsing the code base will be
+able to understand the error messages or trace the flow of a function
+they want to call. If you're using recursive template instantiations
+or type lists or metafunctions or expression templates, or relying on
+SFINAE or on the sizeof
trick for detecting function
+overload resolution, then there's a good chance you've gone too
+far.
If you use template metaprogramming, you should expect to put +considerable effort into minimizing and isolating the complexity. You +should hide metaprogramming as an implementation detail whenever +possible, so that user-facing headers are readable, and you should +make sure that tricky code is especially well commented. You should +carefully document how the code is used, and you should say something +about what the "generated" code looks like. Pay extra attention to the +error messages that the compiler emits when users make mistakes. The +error messages are part of your user interface, and your code should +be tweaked as necessary so that the error messages are understandable +and actionable from a user point of view.
+ +Boost
+ +Use only approved libraries from the Boost library +collection.
+The + +Boost library collection is a popular collection of +peer-reviewed, free, open-source C++ libraries.
+Boost code is generally very high-quality, is widely +portable, and fills many important gaps in the C++ +standard library, such as type traits and better binders.
+Some Boost libraries encourage coding practices which can +hamper readability, such as metaprogramming and other +advanced template techniques, and an excessively +"functional" style of programming.
+In order to maintain a high level of readability for +all contributors who might read and maintain code, we +only allow an approved subset of Boost features. +Currently, the following libraries are permitted:
+ +-
+
-
+
+ Call Traits from
boost/call_traits.hpp
+
+ -
+ Compressed Pair from
boost/compressed_pair.hpp
+
+ -
+ The Boost Graph Library (BGL) from
boost/graph
, + except serialization (adj_list_serialize.hpp
) and + parallel/distributed algorithms and data structures + (boost/graph/parallel/*
and +boost/graph/distributed/*
).
+
+ -
+ Property Map from
boost/property_map
, except + parallel/distributed property maps (boost/property_map/parallel/*
).
+
+ -
+ Iterator from
boost/iterator
+
+ - The part of
+ Polygon that deals with Voronoi diagram
+ construction and doesn't depend on the rest of
+ Polygon:
+
boost/polygon/voronoi_builder.hpp
, +boost/polygon/voronoi_diagram.hpp
, and +boost/polygon/voronoi_geometry_type.hpp
+
+ -
+ Bimap from
boost/bimap
+
+ -
+ Statistical Distributions and Functions from
+
boost/math/distributions
+
+ -
+ Special Functions from
boost/math/special_functions
+
+ -
+ Multi-index from
boost/multi_index
+
+ -
+ Heap from
boost/heap
+
+ - The flat containers from
+ Container:
+
boost/container/flat_map
, and +boost/container/flat_set
+
+ - Intrusive
+ from
boost/intrusive
.
+
+ - The
+
boost/sort
library.
+
+ - Preprocessor
+ from
boost/preprocessor
.
+
We are actively considering adding other Boost +features to the list, so this list may be expanded in +the future.
+The following libraries are permitted, but their use +is discouraged because they've been superseded by +standard libraries in C++11:
+ +-
+
-
+ Array from
boost/array.hpp
: use + +std::array
instead.
+
+ -
+ Pointer Container from
boost/ptr_container
: use containers of + +std::unique_ptr
instead.
+
std::hash
+ +Do not define specializations of std::hash
.
std::hash<T>
is the function object that the
+C++11 hash containers use to hash keys of type T
,
+unless the user explicitly specifies a different hash function. For
+example, std::unordered_map<int, string>
is a hash
+map that uses std::hash<int>
to hash its keys,
+whereas std::unordered_map<int, string, MyIntHash>
+uses MyIntHash
.
std::hash
is defined for all integral, floating-point,
+pointer, and enum
types, as well as some standard library
+types such as string
and unique_ptr
. Users
+can enable it to work for their own types by defining specializations
+of it for those types.
std::hash
is easy to use, and simplifies the code
+since you don't have to name it explicitly. Specializing
+std::hash
is the standard way of specifying how to
+hash a type, so it's what outside resources will teach, and what
+new engineers will expect.
std::hash
is hard to specialize. It requires a lot
+of boilerplate code, and more importantly, it combines responsibility
+for identifying the hash inputs with responsibility for executing the
+hashing algorithm itself. The type author has to be responsible for
+the former, but the latter requires expertise that a type author
+usually doesn't have, and shouldn't need. The stakes here are high
+because low-quality hash functions can be security vulnerabilities,
+due to the emergence of
+
+hash flooding attacks.
Even for experts, std::hash
specializations are
+inordinately difficult to implement correctly for compound types,
+because the implementation cannot recursively call std::hash
+on data members. High-quality hash algorithms maintain large
+amounts of internal state, and reducing that state to the
+size_t
bytes that std::hash
+returns is usually the slowest part of the computation, so it
+should not be done more than once.
Due to exactly that issue, std::hash
does not work
+with std::pair
or std::tuple
, and the
+language does not allow us to extend it to support them.
You can use std::hash
with the types that it supports
+"out of the box", but do not specialize it to support additional types.
+If you need a hash table with a key type that std::hash
+does not support, consider using legacy hash containers (e.g.
+hash_map
) for now; they use a different default hasher,
+which is unaffected by this prohibition.
If you want to use the standard hash containers anyway, you will +need to specify a custom hasher for the key type, e.g.
+std::unordered_map<MyKeyType, Value, MyKeyTypeHasher> my_map; +
+Consult with the type's owners to see if there is an existing hasher +that you can use; otherwise work with them to provide one, + or roll your own.
+ +We are planning to provide a hash function that can work with any type,
+using a new customization mechanism that doesn't have the drawbacks of
+std::hash
.
C++11
+ +Use libraries and language extensions from C++11 when appropriate. +Consider portability to other environments +before using C++11 features in your +project.
+ +C++11 contains +significant changes both to the language and +libraries.
+C++11 was the official standard until august 2014, and +is supported by most C++ compilers. It standardizes +some common C++ extensions that we use already, allows +shorthands for some operations, and has some performance +and safety improvements.
+The C++11 standard is substantially more complex than +its predecessor (1,300 pages versus 800 pages), and is +unfamiliar to many developers. The long-term effects of +some features on code readability and maintenance are +unknown. We cannot predict when its various features will +be implemented uniformly by tools that may be of +interest, particularly in the case of projects that are +forced to use older versions of tools.
+ +As with Boost, some C++11 +extensions encourage coding practices that hamper +readability—for example by removing +checked redundancy (such as type names) that may be +helpful to readers, or by encouraging template +metaprogramming. Other extensions duplicate functionality +available through existing mechanisms, which may lead to confusion +and conversion costs.
+ + +C++11 features may be used unless specified otherwise. +In addition to what's described in the rest of the style +guide, the following C++11 features may not be used:
+ +-
+
+
+
+
+
+
+
+
+
- Compile-time rational numbers
+ (
<ratio>
), because of concerns that + it's tied to a more template-heavy interface + style.
+
+ - The
<cfenv>
and +<fenv.h>
headers, because many + compilers do not support those features reliably.
+
+ - Ref-qualifiers on member functions, such as
void X::Foo() + &
orvoid X::Foo() &&
, because of concerns + that they're an overly obscure feature.
+
+
+
+
+
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
, designated initializers (e.g.
+ Foo f = {.field = 3}
), inline assembly, __COUNTER__
,
+ __PRETTY_FUNCTION__
, compound statement expressions (e.g.
+ foo = ({ int x; Bar(&x); x })
, variable-length arrays and
+ alloca()
, and the a?:b
syntax.
-
+
- Nonstandard extensions may provide useful features that do not exist + in standard C++. For example, some people think that designated + initializers are more readable than standard C++ features like + constructors. +
- Important performance guidance to the compiler can only be specified + using extensions. +
-
+
- Nonstandard extensions do not work in all compilers. Use of nonstandard + extensions reduces portability of code. +
- Even if they are supported in all targeted compilers, the extensions + are often not well-specified, and there may be subtle behavior differences + between compilers. +
- Nonstandard extensions add to the language features that a reader must + know to understand the code. +
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:
+typedef Foo Bar; +using Bar = Foo; +using other_namespace::Foo; ++ +
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.
+-
+
- Aliases can improve readability by simplifying a long or complicated name. +
- Aliases can reduce duplication by naming in one place a type used repeatedly in an API, + which might make it easier to change the type later. + +
-
+
- When placed in a header where client code can refer to them, aliases increase the + number of entities in that header's API, increasing its complexity. +
- Clients can easily rely on unintended details of public aliases, making + changes difficult. +
- It can be tempting to create a public alias that is only intended for use + in the implementation, without considering its impact on the API, or on maintainability. +
- Aliases can create risk of name collisions +
- Aliases can reduce readability by giving a familiar construct an unfamiliar name +
- Type aliases can create an unclear API contract: + it is unclear whether the alias is guaranteed to be identical to the type it aliases, + to have the same API, or only to be usable in specified narrow ways +
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 of +the new name, including whether it is guaranteed to always be the same as the type +it's currently aliased to, or whether a more limited compatibility is +intended. This lets the user know whether they can treat the types as +substitutable or whether more specific rules must be followed, and can help the +implementation retain some degree of freedom to change the alias.
+Don't put namespace aliases in your public API. (See also Namespaces). +
+ +For example, these aliases document how they are intended to be used in client code:
+namespace a { +// 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::Bar*; + +// A set of measurements. Just an alias for user convenience. +using TimeSeries = std::unordered_set<DataPoint, std::hash<DataPoint>, DataPointComparator>; +} // namespace a ++ +
These aliases don't document intended use, and half of them aren't meant for client use:
+ +namespace a { +// Bad: none of these say how they should be used. +using DataPoint = foo::bar::Bar*; +using std::unordered_set; // Bad: just for local convenience +using std::hash; // Bad: just for local convenience +typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator> TimeSeries; +} // namespace a ++ +
However, local convenience aliases are fine in function definitions, private sections of + classes, explicitly marked internal namespaces, and in .cc files:
+ +// In a .cc file +using std::unordered_set; ++ +
Naming
+ +The most important consistency rules are those that govern +naming. The style of a name immediately informs us what sort of +thing the named entity is: a type, a variable, a function, a +constant, a macro, etc., without requiring us to search for the +declaration of that entity. The pattern-matching engine in our +brains relies a great deal on these naming rules. +
+ +Naming rules are pretty arbitrary, but + we feel that +consistency is more important than individual preferences in this +area, so regardless of whether you find them sensible or not, +the rules are the rules.
+ +General Naming Rules
+ +Names should be descriptive; avoid abbreviation.
+Give as descriptive a name as possible, within reason. +Do not worry about saving horizontal space as it is far +more important to make your code immediately +understandable by a new reader. Do not use abbreviations +that are ambiguous or unfamiliar to readers outside your +project, and do not abbreviate by deleting letters within +a word.
+ +int price_count_reader; // No abbreviation. +int num_errors; // "num" is a widespread convention. +int num_dns_connections; // Most people know what "DNS" stands for. ++ +
int n; // Meaningless. +int nerr; // Ambiguous abbreviation. +int n_comp_conns; // Ambiguous abbreviation. +int wgc_connections; // Only your group knows what this stands for. +int pc_reader; // Lots of things can be abbreviated "pc". +int cstmr_id; // Deletes internal letters. ++ +
Note that certain universally-known abbreviations are OK, such as
+i
for an iteration variable and T
for a
+template parameter.
Template parameters should follow the naming style for their +category: type template parameters should follow the rules for +type names, and non-type template +parameters should follow the rules for +variable names. + +
File Names
+ +Filenames should be all lowercase and can include
+underscores (_
) or dashes (-
).
+Follow the convention that your
+
+project uses. If there is no consistent
+local pattern to follow, prefer "_".
Examples of acceptable file names:
+ +-
+
my_useful_class.cc
+ my-useful-class.cc
+ myusefulclass.cc
+ myusefulclass_test.cc // _unittest and _regtest are deprecated.
+
C++ files should end in .cc
and header files should end in
+.h
. Files that rely on being textually included at specific points
+should end in .inc
(see also the section on
+self-contained headers).
Do not use filenames that already exist in
+/usr/include
, such as db.h
.
In general, make your filenames very specific. For
+example, use http_server_logs.h
rather than
+logs.h
. A very common case is to have a pair
+of files called, e.g., foo_bar.h
and
+foo_bar.cc
, defining a class called
+FooBar
.
Inline functions must be in a .h
file. If
+your inline functions are very short, they should go
+directly into your .h
file.
Type Names
+ +Type names start with a capital letter and have a capital
+letter for each new word, with no underscores:
+MyExcitingClass
, MyExcitingEnum
.
The names of all types — classes, structs, type aliases, +enums, and type template parameters — have the same naming convention. +Type names should start with a capital letter and have a capital letter +for each new word. No underscores. For example:
+ +// classes and structs +class UrlTable { ... +class UrlTableTester { ... +struct UrlTableProperties { ... + +// typedefs +typedef hash_map<UrlTableProperties *, string> PropertiesMap; + +// using aliases +using PropertiesMap = hash_map<UrlTableProperties *, string>; + +// enums +enum UrlTableErrors { ... ++ +
Variable Names
+ +The names of variables (including function parameters) and data members are
+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:
+ +string table_name; // OK - uses underscore. +string tablename; // OK - all lowercase. ++ +
string tableName; // Bad - mixed case. ++ +
Class Data Members
+ +Data members of classes, both static and non-static, are +named like ordinary nonmember variables, but with a +trailing underscore.
+ +class TableInfo { + ... + private: + string table_name_; // OK - underscore at end. + string tablename_; // OK. + 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 have +the trailing underscores that data members in classes have.
+ +struct UrlTableProperties { + string name; + int num_entries; + static Pool<UrlTableProperties>* pool; +}; ++ + +
See Structs vs. +Classes for a discussion of when to use a struct +versus a class.
+ +Constant Names
+ +Variables declared constexpr or const, and whose value is fixed for + the duration of the program, are named with a leading "k" followed + by mixed case. For example:
+const int kDaysInAWeek = 7; ++ +
All such variables with static storage duration (i.e. statics and globals, + see + Storage Duration for details) should be named this way. This + convention is optional for variables of other storage classes, e.g. automatic + variables, otherwise the usual variable naming rules apply.
+ +
Function Names
+ +Regular functions have mixed case; accessors and mutators may be named +like variables.
+Ordinarily, functions should start with a capital letter and have a
+capital letter for each new word
+(a.k.a. "Camel
+Case" or "Pascal case"). Such names should not have
+underscores. Prefer to capitalize acronyms as single words
+(i.e. StartRpc()
, not StartRPC()
).
AddTableEntry() +DeleteUrl() +OpenFileOrDie() ++ +
(The same naming rule applies to class- and namespace-scope +constants that are exposed as part of an API and that are intended to look +like functions, because the fact that they're +objects rather than functions is an unimportant implementation detail.)
+ +Accessors and mutators (get and set functions) may be named like
+variables. These often correspond to actual member variables, but this is
+not required. For example, int count()
and void
+set_count(int count)
.
Namespace Names
+ +The name of a top-level namespace should usually be the +name of the project or team whose code is contained in that +namespace. The code in that namespace should usually be in +a directory whose basename matches the namespace name (or +subdirectories thereof).
+ + + + + +Keep in mind that the rule +against abbreviated names applies to namespaces just as much +as variable names. Code inside the namespace seldom needs to +mention the namespace name, so there's usually no particular need +for abbreviation anyway.
+ +Avoid nested namespaces that match well-known top-level
+namespaces. Collisions between namespace names can lead to surprising
+build breaks because of name lookup rules. In particular, do not
+create any nested std
namespaces. Prefer unique project
+identifiers
+(websearch::index
, websearch::index_util
)
+over collision-prone names like websearch::util
.
For internal
namespaces, be wary of other code being
+added to the same internal
namespace causing a collision
+(internal helpers within a team tend to be related and may lead to
+collisions). In such a situation, using the filename to make a unique
+internal name is helpful
+(websearch::index::frobber_internal
for use
+in frobber.h
)
Enumerator Names
+ +Enumerators (for both scoped and unscoped enums) should be named either like
+constants or like
+macros: either kEnumName
or
+ENUM_NAME
.
Preferably, the individual enumerators should be named
+like constants. However, it
+is also acceptable to name them like
+macros. The enumeration name,
+UrlTableErrors
(and
+AlternateUrlTableErrors
), is a type, and
+therefore mixed case.
enum UrlTableErrors { + kOK = 0, + kErrorOutOfMemory, + kErrorMalformedInput, +}; +enum AlternateUrlTableErrors { + OK = 0, + OUT_OF_MEMORY = 1, + MALFORMED_INPUT = 2, +}; ++ +
Until January 2009, the style was to name enum values +like macros. This caused +problems with name collisions between enum values and +macros. Hence, the change to prefer constant-style naming +was put in place. New code should prefer constant-style +naming if possible. However, there is no reason to change +old code to use constant-style names, unless the old +names are actually causing a compile-time problem.
+ + + +Macro Names
+ +You're not really going to
+define a macro, are you? If you do, they're like this:
+MY_MACRO_THAT_SCARES_SMALL_CHILDREN
.
Please see the description +of macros; in general macros should not be used. +However, if they are absolutely needed, then they should be +named with all capitals and underscores.
+ +#define ROUND(x) ... +#define PI_ROUNDED 3.0 ++ +
Exceptions to Naming Rules
+ +If you are naming something that is analogous to an +existing C or C++ entity then you can follow the existing +naming convention scheme.
+-
+
bigopen()
+ - function name, follows form of
open()
+
+ uint
+ typedef
+
+ bigpos
+ struct
orclass
, follows + form ofpos
+
+ sparse_hash_map
+ - STL-like entity; follows STL naming conventions + +
LONGLONG_MAX
+ - a constant, as in
INT_MAX
+
Comments
+ +Though a pain to write, comments are absolutely vital to +keeping our code readable. The following rules describe what +you should comment and where. But remember: while comments are +very important, the best code is self-documenting. Giving +sensible names to types and variables is much better than using +obscure names that you must then explain through comments.
+ +When writing your comments, write for your audience: the +next +contributor who will need to +understand your code. Be generous — the next +one may be you!
+ +Comment Style
+ +Use either the //
or /* */
+syntax, as long as you are consistent.
You can use either the //
or the /*
+*/
syntax; however, //
is
+much more common. Be consistent with how you
+comment and what style you use where.
File Comments
+ +Start each file with license boilerplate.
+ +File comments describe the contents of a file. If a file declares, +implements, or tests exactly one abstraction that is documented by a comment +at the point of declaration, file comments are not required. All other files +must have file comments.
+ +Legal Notice and Author +Line
+ + + +Every file should contain license +boilerplate. Choose the appropriate boilerplate for the +license used by the project (for example, Apache 2.0, +BSD, LGPL, GPL).
+ +If you make significant changes to a file with an +author line, consider deleting the author line.
+ +File Contents
+ +If a .h
declares multiple abstractions, the file-level comment
+should broadly describe the contents of the file, and how the abstractions are
+related. A 1 or 2 sentence file-level comment may be sufficient. The detailed
+documentation about individual abstractions belongs with those abstractions,
+not at the file level.
Do not duplicate comments in both the .h
and the
+.cc
. Duplicated comments diverge.
Class Comments
+ +Every non-obvious class declaration should have an accompanying +comment that describes what it is for and how it should be used.
+// Iterates over the contents of a GargantuanTable. +// Example: +// GargantuanTableIterator* iter = table->NewIterator(); +// for (iter->Seek("foo"); !iter->done(); iter->Next()) { +// process(iter->key(), iter->value()); +// } +// delete iter; +class GargantuanTableIterator { + ... +}; ++ +
The class comment should provide the reader with enough information to know +how and when to use the class, as well as any additional considerations +necessary to correctly use the class. Document the synchronization assumptions +the class makes, if any. If an instance of the class can be accessed by +multiple threads, take extra care to document the rules and invariants +surrounding multithreaded use.
+ +The class comment is often a good place for a small example code snippet +demonstrating a simple and focused usage of the class.
+ +When sufficiently separated (e.g. .h
and .cc
+files), comments describing the use of the class should go together with its
+interface definition; comments about the class operation and implementation
+should accompany the implementation of the class's methods.
Function Comments
+ +Declaration comments describe use of the function (when it is +non-obvious); comments at the definition of a function describe +operation.
+Function Declarations
+ +Almost every function declaration should have comments immediately +preceding it that describe what the function does and how to use +it. These comments may be omitted only if the function is simple and +obvious (e.g. simple accessors for obvious properties of the +class). These comments should be descriptive ("Opens the file") +rather than imperative ("Open the file"); the comment describes the +function, it does not tell the function what to do. In general, these +comments do not describe how the function performs its task. Instead, +that should be left to comments in the function definition.
+ +Types of things to mention in comments at the function +declaration:
+ +-
+
- What the inputs and outputs are. + +
- For class member functions: whether the object + remembers reference arguments beyond the duration of + the method call, and whether it will free them or + not. + +
- If the function allocates memory that the caller + must free. + +
- Whether any of the arguments can be a null + pointer. + +
- If there are any performance implications of how a + function is used. + +
- If the function is re-entrant. What are its + synchronization assumptions? +
Here is an example:
+ +// Returns an iterator for this table. It is the client's +// responsibility to delete the iterator when it is done with it, +// and it must not use the iterator once the GargantuanTable object +// on which the iterator was created has been deleted. +// +// The iterator is initially positioned at the beginning of the table. +// +// This method is equivalent to: +// Iterator* iter = table->NewIterator(); +// iter->Seek(""); +// return iter; +// If you are going to immediately seek to another place in the +// returned iterator, it will be faster to use NewIterator() +// and avoid the extra seek. +Iterator* GetIterator() const; ++ +
However, do not be unnecessarily verbose or state the +completely obvious. Notice below that it is not necessary + to say "returns false otherwise" because this is +implied.
+ +// Returns true if the table cannot hold any more entries. +bool IsTableFull(); ++ +
When documenting function overrides, focus on the +specifics of the override itself, rather than repeating +the comment from the overridden function. In many of these +cases, the override needs no additional documentation and +thus no comment is required.
+ +When commenting constructors and destructors, remember +that the person reading your code knows what constructors +and destructors are for, so comments that just say +something like "destroys this object" are not useful. +Document what constructors do with their arguments (for +example, if they take ownership of pointers), and what +cleanup the destructor does. If this is trivial, just +skip the comment. It is quite common for destructors not +to have a header comment.
+ +Function Definitions
+ +If there is anything tricky about how a function does +its job, the function definition should have an +explanatory comment. For example, in the definition +comment you might describe any coding tricks you use, +give an overview of the steps you go through, or explain +why you chose to implement the function in the way you +did rather than using a viable alternative. For instance, +you might mention why it must acquire a lock for the +first half of the function but why it is not needed for +the second half.
+ +Note you should not just repeat the comments
+given with the function declaration, in the
+.h
file or wherever. It's okay to
+recapitulate briefly what the function does, but the
+focus of the comments should be on how it does it.
Variable Comments
+ +In general the actual name of the variable should be +descriptive enough to give a good idea of what the variable +is used for. In certain cases, more comments are required.
+Class Data Members
+ +The purpose of each class data member (also called an instance
+variable or member variable) must be clear. If there are any
+invariants (special values, relationships between members, lifetime
+requirements) not clearly expressed by the type and name, they must be
+commented. However, if the type and name suffice (int
+num_events_;
), no comment is needed.
In particular, add comments to describe the existence and meaning +of sentinel values, such as nullptr or -1, when they are not +obvious. 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 they +are, what they are used for, and (if unclear) why it needs to be +global. For example:
+ +// The total number of tests 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 comments +before them. Example:
+ +// Divide result by two, taking into account that x +// contains the carry from the add. +for (int i = 0; i < result->size(); i++) { + x = (x << 8) + (*result)[i]; + (*result)[i] = x >> 1; + x &= 1; +} ++ +
Line Comments
+ +Also, lines that are non-obvious should get a comment +at the end of the line. These end-of-line comments should +be separated from the code by 2 spaces. Example:
+ +// If we have enough memory, mmap the data portion too. +mmap_budget = max<int64>(0, mmap_budget - index_->length()); +if (mmap_budget >= data_size_ && !MmapData(mmap_chunk_bytes, mlock)) + return; // Error already logged. ++ +
Note that there are both comments that describe what +the code is doing, and comments that mention that an +error has already been logged when the function +returns.
+ +If you have several comments on subsequent lines, it +can often be more readable to line them up:
+ +DoSomething(); // Comment here so the comments line up. +DoSomethingElseThatIsLonger(); // Two spaces between the code and the comment. +{ // One space before comment when opening a new scope is allowed, + // thus the comment lines up with the following comments and code. + DoSomethingElse(); // Two spaces before line comments normally. +} +std::vector<string> list{ + // Comments in braced lists describe the next element... + "First item", + // .. and should be aligned appropriately. + "Second item"}; +DoSomething(); /* For trailing block comments, one space is fine. */ ++ +
Function Argument Comments
+ +When the meaning of a function argument is nonobvious, consider +one of the following remedies:
+ +-
+
- If the argument is a literal constant, and the same constant is + used in multiple function calls in a way that tacitly assumes they're + the same, you should use a named constant to make that constraint + explicit, and to guarantee that it holds. + +
- Consider changing the function signature to replace a
bool
+ argument with anenum
argument. This will make the argument + values self-describing.
+
+ - For functions that have several configuration options, consider + defining a single class or struct to hold all the options + , + and pass an instance of that. + This approach has several advantages. Options are referenced by name + at the call site, which clarifies their meaning. It also reduces + function argument count, which makes function calls easier to read and + write. As an added benefit, you don't have to change call sites when + you add another option. + + +
- Replace large or complex nested expressions with named variables. + +
- As a last resort, use comments to clarify argument meanings at the + call site. +
// 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 what +code does, unless the behavior is nonobvious to a reader who understands +C++ well. Instead, provide higher level comments that describe why +the code does what it does, or make the code self describing.
+ +Compare this: + +// Find the element in the vector. <-- Bad: obvious! +auto iter = std::find(v.begin(), v.end(), element); +if (iter != v.end()) { + Process(element); +} ++ +To this: + +
// Process "element" unless it was already processed. +auto iter = std::find(v.begin(), v.end(), element); +if (iter != v.end()) { + Process(element); +} ++ +Self-describing code doesn't need a comment. The comment from +the example above would be obvious: + +
if (!IsAlreadyProcessed(element)) { + Process(element); +} ++ +
Punctuation, Spelling and Grammar
+ +Pay attention to punctuation, spelling, and grammar; it is +easier to read well-written comments than badly written +ones.
+Comments should be as readable as narrative text, with +proper capitalization and punctuation. In many cases, +complete sentences are more readable than sentence +fragments. Shorter comments, such as comments at the end +of a line of code, can sometimes be less formal, but you +should be consistent with your style.
+ +Although it can be frustrating to have a code reviewer +point out that you are using a comma when you should be +using a semicolon, it is very important that source code +maintain a high level of clarity and readability. Proper +punctuation, spelling, and grammar help with that +goal.
+ +TODO Comments
+ +Use TODO
comments for code that is temporary,
+a short-term solution, or good-enough but not perfect.
TODO
s should include the string
+TODO
in all caps, followed by the
+
+name, e-mail address, bug ID, or other
+identifier
+of the person or issue with the best context
+about the problem referenced by the TODO
. The
+main purpose is to have a consistent TODO
that
+can be searched to find out how to get more details upon
+request. A TODO
is not a commitment that the
+person referenced will fix the problem. Thus when you create
+a TODO
with a name, it is almost always your
+name that is given.
// TODO(kl@gmail.com): Use a "*" here for concatenation operator. +// TODO(Zeke) change this to use relations. +// TODO(bug 12345): remove the "Last visitors" feature ++
If your TODO
is of the form "At a future
+date do something" make sure that you either include a
+very specific date ("Fix by November 2005") or a very
+specific event ("Remove this code when all clients can
+handle XML responses.").
Deprecation Comments
+ +Mark deprecated interface points with DEPRECATED
+comments.
You can mark an interface as deprecated by writing a
+comment containing the word DEPRECATED
in
+all caps. The comment goes either before the declaration
+of the interface or on the same line as the
+declaration.
After the word
+DEPRECATED
, write your name, e-mail address,
+or other identifier in parentheses.
A deprecation comment must include simple, clear +directions for people to fix their callsites. In C++, you +can implement a deprecated function as an inline function +that calls the new interface point.
+ +Marking an interface point DEPRECATED
+will not magically cause any callsites to change. If you
+want people to actually stop using the deprecated
+facility, you will have to fix the callsites yourself or
+recruit a crew to help you.
New code should not contain calls to deprecated +interface points. Use the new interface point instead. If +you cannot understand the directions, find the person who +created the deprecation and ask them for help using the +new interface point.
+ + + +Formatting
+ +Coding style and formatting are pretty arbitrary, but a + +project is much easier to follow +if everyone uses the same style. Individuals may not agree with every +aspect of the formatting rules, and some of the rules may take +some getting used to, but it is important that all + +project contributors follow the +style rules so that +they can all read and understand +everyone's code easily.
+ + + +To help you format code correctly, we've +created a + +settings file for emacs.
+ +Line Length
+ +Each line of text in your code should be at most 80 +characters long.
+We recognize that this rule is +controversial, but so much existing code already adheres +to it, and we feel that consistency is important.
+ +Those who favor this rule +argue that it is rude to force them to resize +their windows and there is no need for anything longer. +Some folks are used to having several code windows +side-by-side, and thus don't have room to widen their +windows in any case. People set up their work environment +assuming a particular maximum window width, and 80 +columns has been the traditional standard. Why change +it?
+Proponents of change argue that a wider line can make +code more readable. The 80-column limit is an hidebound +throwback to 1960s mainframes; modern equipment has wide screens that +can easily show longer lines.
+80 characters is the maximum.
+ +Comment lines can be longer than 80 +characters if it is not feasible to split them without +harming readability, ease of cut and paste or auto-linking +-- e.g. if a line contains an example command or a literal +URL longer than 80 characters.
+ +A raw-string literal may have content +that exceeds 80 characters. Except for test code, such literals +should appear near the top of a file.
+ +An #include
statement with a
+long path may exceed 80 columns.
You needn't be concerned about +header guards that exceed +the maximum length.
+Non-ASCII Characters
+ +Non-ASCII characters should be rare, and must use UTF-8 +formatting.
+You shouldn't hard-code user-facing text in source, +even English, so use of non-ASCII characters should be +rare. However, in certain cases it is appropriate to +include such words in your code. For example, if your +code parses data files from foreign sources, it may be +appropriate to hard-code the non-ASCII string(s) used in +those data files as delimiters. More commonly, unittest +code (which does not need to be localized) might +contain non-ASCII strings. In such cases, you should use +UTF-8, since that is an encoding +understood by most tools able to handle more than just +ASCII.
+ +Hex encoding is also OK, and encouraged where it
+enhances readability — for example,
+"\xEF\xBB\xBF"
, or, even more simply,
+u8"\uFEFF"
, is the Unicode zero-width
+no-break space character, which would be invisible if
+included in the source as straight UTF-8.
Use the u8
prefix
+to guarantee that a string literal containing
+\uXXXX
escape sequences is encoded as UTF-8.
+Do not use it for strings containing non-ASCII characters
+encoded as UTF-8, because that will produce incorrect
+output if the compiler does not interpret the source file
+as UTF-8.
You shouldn't use the C++11 char16_t
and
+char32_t
character types, since they're for
+non-UTF-8 text. For similar reasons you also shouldn't
+use wchar_t
(unless you're writing code that
+interacts with the Windows API, which uses
+wchar_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 your +code. You should set your editor to emit spaces when you +hit the tab key.
+ +Function Declarations and Definitions
+ +Return type on the same line as function name, parameters +on the same line if they fit. Wrap parameter lists which do +not fit on a single line as you would wrap arguments in a +function 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:
+ +-
+
- Choose good parameter names. + +
- Parameter names may be omitted only if the parameter is unused and its + purpose is obvious. + +
- If you cannot fit the return type and the function + name on a single line, break between them. + +
- If you break after the return type of a function + declaration or definition, do not indent. + +
- The open parenthesis is always on the same line as + the function name. + +
- There is never a space between the function name + and the open parenthesis. + +
- There is never a space between the parentheses and + the parameters. + +
- The open curly brace is always on the end of the last line of the function + declaration, not the start of the next line. + +
- The close curly brace is either on the last line by + itself or on the same line as the open curly brace. + +
- There should be a space between the close + parenthesis and the open curly brace. + +
- All parameters should be aligned if possible. + +
- Default indentation is 2 spaces. + +
- Wrapped parameters have a 4 space indent. +
Unused parameters that are obvious from context may be omitted:
+ +class Foo { + public: + Foo(Foo&&); + Foo(const Foo&); + Foo& operator=(Foo&&); + Foo& operator=(const Foo&); +}; ++ +
Unused parameters that might not be obvious should comment out the variable +name 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 very +beginning of the function declaration or definition, before the +return type:
+MUST_USE_RESULT bool IsOK(); ++ +
Lambda Expressions
+ +Format parameters and bodies as for any other function, and capture +lists like other comma-separated lists.
+For by-reference captures, do not leave a space between the +ampersand (&) 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.
+std::set<int> blacklist = {7, 8, 9}; +std::vector<int> digits = {3, 9, 1, 8, 4, 7, 1}; +digits.erase(std::remove_if(digits.begin(), digits.end(), [&blacklist](int i) { + return blacklist.find(i) != blacklist.end(); + }), + digits.end()); ++ +
Function Calls
+ +Either write the call all on a single line, wrap the +arguments at the parenthesis, or start the arguments on a new +line indented by four spaces and continue at that 4 space +indent. In the absence of other considerations, use the +minimum number of lines, including placing multiple arguments +on 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, they +should be broken up onto multiple lines, with each +subsequent line aligned with the first argument. Do not +add spaces after the open paren or before the close +paren:
+bool result = DoSomething(averyveryveryverylongargument1, + argument2, argument3); ++ +
Arguments may optionally all be placed on subsequent +lines 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 the +number of lines necessary for calling a function unless +there is a specific readability problem. Some find that +formatting with strictly one argument on each line is +more readable and simplifies editing of the arguments. +However, we prioritize for the reader over the ease of +editing arguments, and most readability problems are +better addressed with the following techniques.
+ +If having multiple arguments in a single line decreases +readability due to the complexity or confusing nature of the +expressions that make up some arguments, try creating +variables 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 with +an explanatory comment:
+bool result = DoSomething(scores[x] * y + bases[x], // Score heuristic. + x, y, z); ++ +
If there is still a case where one argument is +significantly more readable on its own line, then put it on +its own line. The decision should be specific to the argument +which is made more readable rather than a general policy.
+ +Sometimes arguments form a structure that is important +for readability. In those cases, feel free to format the +arguments 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 function call in its place.
+If the braced list follows a name (e.g. a type or
+variable name), format as if the {}
were the
+parentheses of a function call with that name. If there
+is 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}}; ++ +
Conditionals
+ +Prefer no spaces inside parentheses. The if
+and else
keywords belong on separate lines.
There are two acceptable formats for a basic +conditional statement. One includes spaces between the +parentheses and the condition, and one does not.
+ +The most common form is without spaces. Either is +fine, but be consistent. If you are modifying a +file, use the format that is already present. If you are +writing new code, use the format that the other files in +that directory or project use. If in doubt and you have +no personal preference, do not add the spaces.
+ +if (condition) { // no spaces inside parentheses + ... // 2 space indent. +} else if (...) { // The else goes on the same line as the closing brace. + ... +} else { + ... +} ++ +
If you prefer you may add spaces inside the +parentheses:
+ +if ( condition ) { // spaces inside parentheses - rare + ... // 2 space indent. +} else { // The else goes on the same line as the closing brace. + ... +} ++ +
Note that in all cases you must have a space between
+the if
and the open parenthesis. You must
+also have a space between the close parenthesis and the
+curly brace, if you're using one.
if(condition) { // Bad - space missing after IF. +if (condition){ // Bad - space missing before {. +if(condition){ // Doubly bad. ++ +
if (condition) { // Good - proper space after IF and before {. ++ +
Short conditional statements may be written on one
+line if this enhances readability. You may use this only
+when the line is brief and the statement does not use the
+else
clause.
if (x == kFoo) return new Foo(); +if (x == kBar) return new Bar(); ++ +
This is not allowed when the if statement has an
+else
:
// Not allowed - IF statement on one line when there is an ELSE clause +if (x) DoThis(); +else DoThat(); ++ +
In general, curly braces are not required for
+single-line statements, but they are allowed if you like
+them; conditional or loop statements with complex
+conditions or statements may be more readable with curly
+braces. Some
+projects require that an
+if
must always always have an accompanying
+brace.
if (condition) + DoSomething(); // 2 space indent. + +if (condition) { + DoSomething(); // 2 space indent. +} ++ +
However, if one part of an
+if
-else
statement uses curly
+braces, the other part must too:
// Not allowed - curly on IF but not ELSE +if (condition) { + foo; +} else + bar; + +// Not allowed - curly on ELSE but not IF +if (condition) + foo; +else { + bar; +} ++ +
// Curly braces around both IF and ELSE required because +// one of the clauses used braces. +if (condition) { + foo; +} else { + bar; +} ++ +
Loops and Switch Statements
+ +Switch statements may use braces for blocks. Annotate
+non-trivial fall-through between cases.
+Braces are optional for single-statement loops.
+Empty loop bodies should use empty braces or continue
.
case
blocks in switch
+statements can have curly braces or not, depending on
+your preference. If you do include curly braces they
+should be placed as shown below.
If not conditional on an enumerated value, switch
+statements should always have a default
case
+(in the case of an enumerated value, the compiler will
+warn you if any values are not handled). If the default
+case should never execute, simply
+assert
:
switch (var) { + case 0: { // 2 space indent + ... // 4 space indent + break; + } + case 1: { + ... + break; + } + default: { + assert(false); + } +} ++
Braces are optional for single-statement loops.
+ +for (int i = 0; i < kSomeNumber; ++i) + printf("I love you\n"); + +for (int i = 0; i < kSomeNumber; ++i) { + printf("I take it back\n"); +} ++ + +
Empty loop bodies should use an empty pair of braces or continue
,
+but not a single semicolon.
while (condition) { + // Repeat test until it returns false. +} +for (int i = 0; i < kSomeNumber; ++i) {} // Good - one newline is also OK. +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 not +have trailing spaces.
+The following are examples of correctly-formatted +pointer and reference expressions:
+ +x = *p; +p = &x; +x = r.y; +x = r->y; ++ +
Note that:
+ +-
+
- There are no spaces around the period or arrow when + accessing a member. + +
- Pointer operators have no space after the
+
*
or&
.
+
When declaring a pointer variable or argument, you may +place the asterisk adjacent to either the type or to the +variable name:
+ +// These are fine, space preceding. +char *c; +const string &str; + +// These are fine, space following. +char* c; +const string& str; ++ +It is allowed (if unusual) to declare multiple variables in the same +declaration, but it is disallowed if any of those have pointer or +reference decorations. Such declarations are easily misread. +
// Fine if helpful for readability. +int x, y; ++
int x, *y; // Disallowed - no & or * in multiple declaration +char * c; // Bad - spaces on both sides of * +const string & str; // Bad - spaces on both sides of & ++ +
You should do this consistently within a single +file, +so, when modifying an existing file, use the style in +that file.
+ +Boolean Expressions
+ +When you have a boolean expression that is longer than the +standard line length, be +consistent in how you break up the lines.
+In this example, the logical AND operator is always at +the 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 of
+the &&
logical AND operators are at
+the end of the line. This is more common in Google code,
+though wrapping all operators at the beginning of the
+line is also allowed. Feel free to insert extra
+parentheses judiciously because they can be very helpful
+in increasing readability when used
+appropriately. Also note that you should always use
+the punctuation operators, such as
+&&
and ~
, rather than
+the word operators, such as and
and
+compl
.
Return Values
+ +Do not needlessly surround the return
+expression with parentheses.
Use parentheses in return expr;
only
+where you would use them in x = 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
+ +Your choice of =
, ()
, or
+{}
.
You may choose between =
,
+()
, and {}
; the following are
+all correct:
int x = 3; +int x(3); +int x{3}; +string name = "Some Name"; +string name("Some Name"); +string name{"Some Name"}; ++ +
Be careful when using a braced initialization list {...}
+on a type with an std::initializer_list
constructor.
+A nonempty braced-init-list prefers the
+std::initializer_list
constructor whenever
+possible. Note that empty braces {}
are special, and
+will call a default constructor if available. To force the
+non-std::initializer_list
constructor, use parentheses
+instead of braces.
std::vector<int> v(100, 1); // A vector of 100 1s. +std::vector<int> v{100, 1}; // A vector of 100, 1. ++ +
Also, the brace form prevents narrowing of integral +types. This can prevent some types of programming +errors.
+ +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 should +always be at the beginning of the line.
+Even when preprocessor directives are within the body +of indented code, the directives should start at the +beginning 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 in public
, protected
and
+private
order, each indented one space.
The basic format for a class definition (lacking the +comments, see Class +Comments for a discussion of what comments are +needed) 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:
+ +-
+
- Any base class name should be on the same line as + the subclass name, subject to the 80-column limit. + +
- The
public:
,protected:
, + andprivate:
keywords should be indented + one space.
+
+ - Except for the first instance, these keywords + should be preceded by a blank line. This rule is + optional in small classes. + +
- Do not leave a blank line after these + keywords. + +
- The
public
section should be first, + followed by theprotected
and finally the +private
section.
+
+ - See Declaration + Order for rules on ordering declarations within + each of these sections. +
Constructor Initializer Lists
+ +Constructor initializer lists can be all on one line or +with 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 an +extra 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 ++ +
When declaring nested namespaces, put each namespace +on its own line.
+ +namespace foo { +namespace bar { ++ +
Horizontal Whitespace
+ +Use of horizontal whitespace depends on location. Never put +trailing whitespace at the end of a line.
+General
+ +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 for +others editing the same file, when they merge, as can +removing existing trailing whitespace. So: Don't +introduce trailing whitespace. Remove it if you're +already changing that line, or do it in a separate +clean-up +operation (preferably when no-one +else 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 cast +std::vector<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 when you don't have to. In particular, don't put +more than one or two blank lines between functions, +resist starting functions with a blank line, don't end +functions with a blank line, and be discriminating with +your use of blank lines inside functions.
+ +The basic principle is: The more code that fits on one +screen, the easier it is to follow and understand the +control flow of the program. Of course, readability can +suffer from code being too dense as well as too spread +out, so use your judgement. But in general, minimize use +of vertical whitespace.
+ +Some rules of thumb to help when blank lines may be +useful:
+ +-
+
- Blank lines at the beginning or end of a function + very rarely help readability. + +
- Blank lines inside a chain of if-else blocks may + well help readability. +
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 that +does not conform to this style guide.
+If you find yourself modifying code that was written +to specifications other than those presented by this +guide, you may have to diverge from these rules in order +to stay consistent with the local conventions in that +code. If you are in doubt about how to do this, ask the +original author or the person currently responsible for +the code. Remember that consistency includes +local consistency, too.
+ +Windows Code
+ +Windows +programmers have developed their own set of coding +conventions, mainly derived from the conventions in Windows +headers and other Microsoft code. We want to make it easy +for anyone to understand your code, so we have a single set +of guidelines for everyone writing C++ on any platform.
+It is worth reiterating a few of the guidelines that +you might forget if you are used to the prevalent Windows +style:
+ +-
+
- Do not use Hungarian notation (for example, naming
+ an integer
iNum
). Use the Google naming + conventions, including the.cc
extension + for source files.
+
+ - Windows defines many of its own synonyms for
+ primitive types, such as
DWORD
, +HANDLE
, etc. It is perfectly acceptable, + and encouraged, that you use these types when calling + Windows API functions. Even so, keep as close as you + can to the underlying C++ types. For example, use +const TCHAR *
instead of +LPCTSTR
.
+
+ - When compiling with Microsoft Visual C++, set the + compiler to warning level 3 or higher, and treat all + warnings as errors. + +
- Do not use
#pragma once
; instead use + the standard Google include guards. The path in the + include guards should be relative to the top of your + project tree.
+
+ - In fact, do not use any nonstandard extensions,
+ like
#pragma
and__declspec
, + unless you absolutely must. Using +__declspec(dllimport)
and +__declspec(dllexport)
is allowed; however, + you must use them through macros such as +DLLIMPORT
andDLLEXPORT
, so + that someone can easily disable the extensions if they + share the code.
+
However, there are just a few rules that we +occasionally need to break on Windows:
+ +-
+
- Normally we forbid + the use of multiple implementation inheritance; + however, it is required when using COM and some ATL/WTL + classes. You may use multiple implementation + inheritance to implement COM or ATL/WTL classes and + interfaces. + +
- Although you should not use exceptions in your own
+ code, they are used extensively in the ATL and some
+ STLs, including the one that comes with Visual C++.
+ When using the ATL, you should define
+
_ATL_NO_EXCEPTIONS
to disable exceptions. + You should investigate whether you can also disable + exceptions in your STL, but if not, it is OK to turn on + exceptions in the compiler. (Note that this is only to + get the STL to compile. You should still not write + exception handling code yourself.)
+
+ - The usual way of working with precompiled headers
+ is to include a header file at the top of each source
+ file, typically with a name like
StdAfx.h
+ orprecompile.h
. To make your code easier + to share with other projects, avoid including this file + explicitly (except inprecompile.cc
), and + use the/FI
compiler option to include the + file automatically.
+
+ - Resource headers, which are usually named
+
resource.h
and contain only macros, do not + need to conform to these style guidelines.
+
Parting Words
+ +Use common sense and BE CONSISTENT.
+ +If you are editing code, take a few minutes to look at the
+code around you and determine its style. If they use spaces
+around their if
clauses, you should, too. If their
+comments have little boxes of stars around them, make your
+comments have little boxes of stars around them too.
The point of having style guidelines is to have a common +vocabulary of coding so people can concentrate on what you are +saying, rather than on how you are saying it. We present global +style rules here so people know the vocabulary. But local style +is also important. If code you add to a file looks drastically +different from the existing code around it, the discontinuity +throws readers out of their rhythm when they go to read it. Try +to avoid this.
+ + + +OK, enough writing about writing code; the code itself is much +more interesting. Have fun!
+ ++ +