enzo
Google C++ Syle Guide
Google C++ Style Guide
Table of Contents
He
Fi
leader
i
Classes
le-
der
les,
lass:
Gov
Specific
Comments
hrpevigoogl.g be alsoguideeppguide id
Self-contained Headers The tidefine Guard
Forward Declarations Inline Functions
Names and Order of Includes
Namespaces Unnamed Namespaces and Static Variables
Nonmember, Static Member, and Global Functions
Local Variables Static and Global Variables
Doing Work in Constructors Implicit Conversions
Copyable and Movable Types Structs vs. Classes
Inheritance Multiple Inheritance Interfaces
Operator Overloading Access Control Declaration Order
General Naming Rules File Names Type Names
Variable Names Constant Names Function Names
Namespace Names Enumerator Names Macro Names
Exceptions fo Naming Rules
Comment Style File Comments Class Comments
Function Comments Variable Comments
Implementation Comments Punctuation, Spelling and
TODO Comments Depracation Commentsezeotr Google C++ Syle Guide
Exceptions: Existing Non-conformant Code Windows Cade
tothe
Rules
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 tum can make cade 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 stil allowing
coders to use C++ language features productively.
Style, also known as readability, is what we call the conventions that govem 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 G
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 ofa 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.
hpsigooge.g iu fs uidecppgui de hit 28ezeotr
‘Google C++ Sle Guide
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 willbe 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 particulary
‘common sub-point ofthis principle: When something surprising or unusual is
happening in a snippet of code (for example, transfer of pointer ownership), leaving
textual hints forthe reader at the point of use is valuable (std: :unique_ptr
demonstrates the ownership transfer unambiguously atthe 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
fr adjust your #includes only work properly when your code is consistent with the
‘expectations of the tooling. In many cases, rules that are attributed to "Be Consistent"
boll down to "Just pick one and stop worrying about it; the potential value of allowing
{lexibilty 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. Ifa feature in the C++ standard soles a
problem, or if some idiom is widely known and accepted, that's an argument for using
it. Howeter, sometimes standard features and idioms are flawed, or were just designed
without our codebase's needs in mind. In those cases (as described below) i'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, ether 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 pitas.
‘There is a high bar for style guide waivers on such restrictions, because wahing such
rules often directly risks compromising program corectness.
‘Avoid constructs that our average C++ programmer would find tricky or hard to maintain
‘C4 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 ofthe codebase, When in
ddoubl, 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+ milion 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 colisions across
a codebase of hundreds of millions of fines are dificult to work with and hard to avoid it
‘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 ofthis 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.
hpsuigoogle.g iu fs uidecrpgul de hit 378ezeotr Google C++ Syle Guide
°°Header Files
In general, every .cc fle should have an associated .h file. There are some common
exceptions, such as unittests and small .c¢ fles containing just a main() function
Correct use of header fles 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 file.
©Self-contained Headers
Header files should be self-contained (compile on their own) and end in .h. Nor-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 fle as thelr
declarations. The definitions of these constructs must be included into every .cc file that
ses 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 (~in1.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
cone 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 fle.
They might not use header quards, 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
Al header files should have #tdefine guards to prevent multiple inclusion. The format of the
symbol name should be
___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_BAZH_
endif // FOO_BAR_BAZ H_
hpsuigoogle.g iu fs uidecrpgul de hit 478ezeotr Google C++ Syle Guide
°° Forward Declarations
‘Avoid using forward declarations where possible. Just #include the headers you need,
Definition:
A “forward declaratio
definition
is a declaration of a class, function, or template without an associated
Pros:
+ Forward declarations can save compile time, as includes force the compiler to open
more files and process more input.
+ Forward declarations can save on unnecessary recompilation. ##includes 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 dificult 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:
If b.
struct B {);
struct D: BQ);
I) good_user.ce:
include "b.
void £(8*);
void F(void*);
void test(D* x) { f(x)5 } // calls F(B*)
Ifthe sinclude was replaced with forward decls for 8 and D, test() would call
f(void*),
+ Forward dectaring multiple symbols from a header can be more verbose than simply
#includeing 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.
Decision:
+ Try to avwid forward declarations of entities defined in another project.
+ When using a function declared in a header fle, always #include that header.
+ When using a class template, prefer to #include its header fle.
Please see Names and Order of Includes for rules about when to #include a header,
Inline Functions
hpsuigoogle.g iu fs uidecrpgul de hit 78ezeotr
Google C++ Syle Guide
Define functions inline only when they are small, say, 10 lines or fewer.
Definition:
You can dectare functions in a way that allows the compiler to expand them inline rather than
calling them through the usual function call mechanism.
Pros:
Inlining @ 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,
Cons:
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 modem processors smaller code usually runs faster due to better use
of the instruction cache,
Decision:
‘A decent rule of thumb is to not inline a funetion ifit 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: i'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, €.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 UNKX 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.ce or dir/foo_test.cc, whose main purpose is to implement or test the stuff in
dir2/foo2.h, order your includes as follows:
1. dir2/foo2.h,
2. C system files.
3. Cr+ system files.
4. Other libraries’ hn files.
5. Your project's .h files.
hpsuigoogle.g iu fs uidecrpgul de hit ans.ezeotr
Google C++ Syle Guide
With the preferred ordering, if dir2/foo2.h omits any necessary includes, the build of
dir/foo.cc of 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
oo.h explicitly demonstrates its intent to provide you the symbols of bar, Howover, any
includes present in the related header do not need to be included again in the related cc (i.e.,
foo.c¢ can rely on foo..'s includes),
For example, the includes in google-awesone-project/src/foo/internal/fooserver.cc
might look like this:
include "foo/server/fooserver.h”
include
include
#include
#include
#include "base/basictypes.h’
include “base/conmandlineflags.
include “foo/server/bar-h"
Exception:
‘Sometimes, systom-speciic 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_OXA1.
ifdef LANG_OOL
#include
#endif // LANG_COAT
“Scoping
°°Namespaces
hpsuigoogle.g iu fs uidecrpgul de hit
08ezeotr
Google C++ Syle Guide
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.
Definition:
Namespaces subdivide the global scope into distinct, named scopes, and so are useful for
preventing name collisions in the global scope.
Pros:
Namespaces provide a method for preventing name conflicts in large programs while allowing
most code to use reasonably short names,
For example, if two diferent 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,
project: :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 ¥ {
void f00()3
3 // namespace Y
3 7/7 namespace X
The expressions x: :Y::f00() and x: :00() are interchangeable. Inline namespaces are
primarily intended for AB! compatibility across versions.
Cons:
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, i's necessary to repeatedly refer to symbols by their fully-qualified names.
For deeply-nested namespaces, this can add a lot of clutter.
Decision:
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 fle after includes, gflags defiitions/declarations
and forward declarations of classes from other namespaces.
J/ In the -h file
anespace mynanespace {
// All declarations are within the namespace scope.
// Notice the lack of indentation.
class MyClass {
public:
void Foo();
psuigoogl.g uals uidecrpguide hit wsezeotr
Google C++ Syle Guide
h
} // namespace mynamespace
// In the .cc file
namespace mynanespace {
// Definition of functions is within scope of the namespace.
void MyClass::Fo0() {
}
} // namespace mynamespace
More complex .cc files might have additional details, like flags or using-declarations.
‘include "a."
DEFINE FLAG(booL, soneflag, false, “dummy flag");
namespace a {
using ::fo0::bar;
s+.code for a... // Code goes against the left margin.
} // namespace a
+ Do not declare anything in namespace st, including forward declarations of standard
library classes, Declaring entities in namespace std 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 fo
+ Do not use Namespace aliases at namespace scope in header files except in
‘explicitly marked intemal-only namespaces, because anything imported into a
namespace in a header file becomes part of the public AP! exported by that fle,
// Shorten access to some commonly used names in .cc files.
namespace baz = ::fo0::bar::bazj
// Shorten access to sone commonly used nanes (ina -h file).
aespace Librarian {
namespace inpl { // Internal, not part of the API.
namespace sidetable = ::pipeline diagnostics: :sidetable;
} // namespace inpl
inline void my_inline_function() {
71 namespace alias local to 2 function (or method).
namespace baz ‘00: sbar::baz3
.
} // namespace librarian
*+ Do not use inline namespaces.
hpsuigoogle.g iu fs uidecrpgul de hit os.ezeotr Google C++ Syle Guide
©°Unnamed Namespaces and Static Variables
When definitions in a .cc fle do not need to be referenced outside that fle, place them in an
unnamed namespace or declare them static. Do not use either of these constructs in .h
files,
Definition:
All declarations can be given intemal linkage by placing them in unnamed namespaces, and
functions and variables can be given intemal linkage by declaring them static. This means
that anything you're declaring can't be accessed from another file, ifa different fle declares
something with the same name, then the two entities are completely independent,
Decision:
Use of internal linkage in .c¢ files is encouraged for all code that does not need to be
referenced elsewhere, Do not use intemal linkage in . 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,
Pros:
Nonmember and static member functions can be useful in some situations. Putting
nonmember functions in a namespace avoids polluting the global namespace.
Cons:
Nonmember and static member functions may make more sense as members of anew
class, especially if they access extemal resources or have significant dependencies.
Decision:
‘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 ina namespace. Rather than
creating classes only to group static member functions which do not share static data, use
namespaces instead. For a header nyproject/Foo_bar.h, for example, write
namespace myproject {
namespace foo_bar {
void Functioni();
void Function2();
psigoogl.g iu fs uidecppguid hit 1075.ezeotr Google C++ Syle Guide
} // namespace foo_bar
} 7 namespace myproject
instead of
namespace myproject {
class Foobar {
public:
static void Functiont();
static void Function2();
b
}' // namespace myproject
you define a nonmember function and it is only needed in its .cc file, use intemal 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,
eg.
int i;
i= £05 // Bad -- initialization separate from declaration.
int j = g()3 // Good -- declaration has initialization.
std::vectorcint> v3
v.push_back(1); // Prefer initializing using brace initialization.
v.push_back(2) 5
st
vector 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 = strehr(str, ‘/')) str = p +25
‘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 implenentation:
for (int i = @; i < 1000000; ++i) {
Foo f; // My ctor and dtor get called 1000000 times each.
.DoSomething (i);
y
It may be more efficient to declare such a variable used in a loop outside that loop:
hpsuigoogle.g iu fs uidecrpgul de hit 08ezeotr
Google C++ Sle Guide
Foo #5 _// My ctor and dtor get called once each.
for (int i = @; 4 < 1¢00000; ++i) {
.DoSonething(i);
y
°Static and Global Variables
Variables of class type with static storage duration are forbidden: they cause haro-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 funetion (such
as getenu), 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
cof whether the termination is by retuming 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 stil running —
pethaps in another thread — tries to access it and fails. Or the destructor for a static string.
\ariable 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 @ handler that needs to run when a program terminates va quick_exit() (lushing logs,
for example), you can register it using at_quick_exit(). (Ifyou have @ 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 []).
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.
hpsuigoogle.g iu fs uidecrpgul de hit 08ezeotr Google C++ Syle Guide
©°Doing Work in Constructors
‘Avoid virtual method calls in constructors, and avoid initialization that can fail if you cant
signal an error.
Definition:
Itis possible to perform arbitrary initialization in the body of the constructor.
Pros:
+ No need to wory 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.
* Ifthe 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 contusion,
+ There is no easy way for constructors to signal errors, short of crashing the program
(not always appropriate) or using exceptions (which are forbidden),
+ Ifthe work fails, we now have an object whose initialization code failed, so it may be
‘an unusual state requiring a bool TsValid() 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.
Decision:
Constructors should never call virtual functions. lf appropriate for your code , terminating the
rogram 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.
Definition:
Implicit conversions allow an object of one type (called the source type) to be used where a
diferent type (called the destination type) is expected, such as when passing an int
argument to a function that takes a double parameter.
In adcition 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 (¢.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)
hpsuigoogle.g iu fs uidecrpgul de hit 1995,ezeotr
Google C++ Syle Guide
‘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, ©.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);
b
void Func(Foo #);
Func({42, 3.14}); // Error
This kind of code isnt technically an implicit conversion, but the language treats it as one as
far as explicit Is concemed,
Pros:
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 altemative to overloading,
List initialization syntax is a concise and expressive way of initializing objects,
Cons:
Implicit comersions 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 singlesargument constructor is not marked explicit, there's no reliable way
to tell whether i'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
Decision:
‘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 nol 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}5)
©Copyable and Movable Types
‘Support copying andlor moving if these operations are clear and meaningful for your type,
Othemwise, disable the implicitly generated special functions that perform copies and moves,
hpsuigoogle.g iu fs uidecrpgul de hit sa.ezeotr
Google C++ Syle Guide
Definition:
A copyable type allows its objects to be initialized or assigned ftom 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 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
e.g. when passing objects by value.
plcitly invoked by the compiler in some situations,
Pros:
Objects of copyable and movable types can be passed and retumed 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
heed to specify them in the contract. it also prevents non-ocal 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 eficient, because
they dontt 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.
Cons:
‘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 dificult 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,
Decision:
Provide the copy and mave 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 efcient than the corresponding
copy operations. tf 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.
lf 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.
hpsuigoogle.g iu fs uidecrpgul de hit 1895ezeotr
Google C++ Sle Guide
class Foo {
public:
Foo(Foo8& other) : field_(other.field) {}
// Bad, defines only nove constructor, but not operators.
private:
Field field;
b
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). f 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
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 behae almost identically in C++. We add our own
semantic meanings to each keyword, so you should use the appropriate keyword for the
datatype 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, ¢.g., constructor, destructor, Initialize(), Reset(), Validate‘),
| more functionality is required, a class is more appropriate. ifin 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.
Definition:
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.
hpsuigoogle.g iu fs uidecrpgul de hit 1818ezeotr
Google C++ Syle Guide
Pros:
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 APL
Cons:
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.
Decision:
Alllinheritance 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 ifit 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 vitual 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 altemative 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 ifthe 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,
Definition:
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.
Pros:
Muttiple implementation inheritance may let you re-use even more code than single
inheritance (see Inheritance).
Cons:
hpsuigoogle.g iu fs uidecrpgul de hit sm.ezeotr
Google C++ Syle Guide
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.
Decision:
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
lend with the Interface suffix
Note:
‘There is an exception to this rule on Windows.
Interfaces
Classes that salisfy certain conditions are allowed, but not required, to end with an
Interface suflx.
Definition:
‘A class is a pure interface ifit meets the following requirements:
+ Ithas only public pure virtual (
destructor).
+ It may not have non-static data members,
+ It need not have any constructors defined. Ifa constructor is provided, it must take no
arguments and it must be protected,
+ Ifitis a subclass, it may only be derived from classes that satisfy these conditions
and are tagged with the Interface suffix.
@") methods and static methods (but see below for
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
Pros:
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
cf multiple inheritance, Additionally, the interface concept is already well-understood by Java
programmers.
Cons:
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.
Decision:
Acclass may end with Interface only ifit meets the above requirements. We do not require
the converse, however: classes that meet the above requirements are not required to end with
Interface.
hpsuigoogle.g iu fs uidecrpgul de hit 1095.ezeotr Google C++ Syle Guide
©°Operator Overloading
Overload operators judiciously. Do not create user-defined literals.
Definition:
C++ permits user code to declare overloaded versions of the builtin 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-comversion functions such as operator bool()
Pros:
Operator overloading can make code more concise and intuitive by enabling user-defined
types to behave the same as builtin 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.
Cons:
+ 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, particulary if the overloaded
‘operator's semantics dont 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, builtin operations.
‘+ Finding the call sites for overloaded operators may require a search tool that's aware of
(G+ syntax, rather than e.g. grep.
+ Ifyou get the argument type of an overloaded operator wrong, you may get a different
‘overfoad 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 vsible. Overioads of &8, ||, and , (comma) cannot match the
evalvation-order semantics of the built4n 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 rur-
time bugs.
+ User-defined literals allow the creation of new syntactic forms that are unfamiliar even
to experienced C++ programmers.
Decision:
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.
hpsuigoogle.g iu fs uidecrpgul de hit 1975ezeotr
Google C++ Syle Guide
all the comparison operators, and make sure < and > never retum true for the same
arguments.
Prefer to define non-modifying binary operators as non-member functions. Ifa binary operator
is defined as a class member, implicit conversions will apply to the right-hand argument, but
not the left-hand one. It wll confuse your users ifa < b compiles but b < a doesnt.
Don't go out of your way to avoid defining operator overloads. For example, prefer to define
and <<, rather than Equals(), CopyFrom(), and PrintTa(). Conversely, don't define
operator overloads just because other libraries expect them. For example, if your type doesnt
have a natural ordering, but you want to store it in a std: :set, use a custom comparator
rather than overloading <
Do not overioad 88, ||, , (comma), or unary &, Do not overload operator’
introduce user-defined literals,
ie, do not
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 trival or
performance-critical, and very short, methods may be defined inline. See Inline Functions for
more details.
°°Functions
©°Parameter Ordering
hpsuigoogle.g iu fs uidecrpgul de hit asezeotr
Google C++ Syle Guide
When defining a function, parameter order is: inputs, then outputs,
Parameters to C/C++ funetions 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-andfast 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, Ifa 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 dificult,
you find that errors are hard to debug, or you want to use a piece of it in several diferent
Contexts, consider breaking up the function into smaller and more manageable pieces,
©°Reference Arguments
Al parameters passed by reference must be labeled const.
Definition:
In C, ifa function needs to modify a variable, the parameter must use a pointer, eg
int foo(int *pval). In C++, the function can alteratively declare a reference parameter:
int foo(int aval).
Pros:
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.
Cons:
References can be confusing, as they have value syntax but pointer semantics,
Decision:
Within function parameter lists all references must be const:
hpsuigoogle.g iu fs uidecrpgul de hit 2sezeotr
Google C++ Sle Guide
void Foo(const string &in, string tout);
In fact tis a very strong convention in Google code that input arguments are values of const
relerences vile oulput arguments are pointers. Input parameters may be const pointers, but
wwe never allow non-const reference parameters except when required by comertion, e.g.
s0ap()
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;
othenvise it will kely confuse readers by making them look for an explanation that doesn't
exist.
©°Function Overloading
Use overloaded functions (including constructors) only ifa reader looking at a call site can get
1a good idea of what is happening without having to fist figure out exactly which overload is
being called.
Definition:
‘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 atext);
void Analyze(const char *text, size_t textlen);
Pros:
COverfoading can make code more intuitive by allowing an identically-named function to take
diferent arguments. It may be necessary for templatized cade, and it can be convenient for
Visitors,
Cons:
Ifa 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.
Decision:
you want to overload a funetion, consider qualifying the name with some information about
the arguments, e.g., AppendStriing(), 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.
hpsuigoogle.g iu fs uidecrpgul de hit ansezeotr Google C++ Syle Guide
°°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 doesnt outweigh
the downsides below,
Pros:
(Often you have a function that uses default values, but occasionally you want to override the
defaulls. 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.
Cons:
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 ae 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 defaul’s value to be fixed al the declaration instead of varying
at each call
Function pointers are confusing in the presence of default arguments, since the function
signature often doesnt match the call signature. Adding function overloads avoids these
problems.
Decision:
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, dont write void #(int n = counter++);.)
In some other cases, default arguments can improve the readability oftheir function
declarations enough to overcome the downsides above, so they are allowed. When in doubt,
use overloads.
Trailing Return Type Syntax
Use trailing retum types only where using the ordinary syntax (leading retum types) is
impractical or much less readable.
Definition:
C++ allows two different forms of function declarations. In the older form, the retum type
appears before the function name, For example:
int foo(int x);
hpsuigoogle.g iu fs uidecrpgul de hit 208ezeotr
Google C++ Syle Guide
The new form, introduced in C++11, uses the auto keyword before the function name and a
trailing retum type atter the argument list. For example, the declaration above could
equivalently be written:
auto foo(int x) -> ints
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.
Pros:
‘Trailing retum 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 retum 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 afer the function's
parameter list has already appeared. This is particularly true when the retum type depends on
template parameters. For example:
template auto add(T t, U u) -> decltype(t + u);
versus
template decltype(declval() + declval()) add(T t
Cons:
‘Trailing retum type syntax is relatively new and it has no analogue in C++-like languages like.
Cand Java, so some readers may find it unfamiliar,
Existing cade bases have an enormous number of function declarations that arent 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.
Decision:
In most cases, continue to use the older style of function declaration where the retum type
goes before the function name, Use the new trailing-retum-type form only in cases where it's
required (Such as lambdas) or where, by putting the type after the function's parameter lst, it
allows you to write the type in a much more readable way. The latter case should be rare; i's
mostly an issue in faiy 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 difler from what you see elsewhere,
°°Ownership and Smart Pointers
hpsuigoogle.g iu fs uidecrpgul de hit 2408ezeotr Google C++ Syle Guide
Prefer to have single, fixed owners for dynamically allocated objects. Prefer to transfer
‘ownership with smart pointers.
Definition:
nership” 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_ptrs 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.
Pros:
+ It's vitually impossible to manage dynamically allocated memory without some sort of
‘ownership logic.
+ Transferring ownership of an object can be cheaper than copying it (copying itis
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.
Cons:
+ 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 altemative to careful ownership design,
‘obfuscating the design of a system.
‘+ Shared ownership requires explicit bookkeeping at run-time, which can be costly.
+ Insome cases (0.9. cyclic references), objects with shared ownership may never be
deleted.
‘Smart pointers are not perfect substitutes for plain pointers.
Decision:
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
hpsuigoogle.g iu fs uidecrpgul de hit 28ezeotr
Google C++ Syle Guide
reference without transferring ownership, Prefer to use std: :unique_ptr to make ownership
transfer explicit. For example:
std: :unique_ptr FooFactory();
void FooConsuner(std: :unique_ptr 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.<.
std::shared_ptr, for example, then auto 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,
‘+ Rialue 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
hpsuigoogle.g iu fs uidecrpgul de hit 2608ezeotr
Google C++ Syle Guide
‘objects. (This is sometimes called "perfect forwarding".)
+ Rialue 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 stil want to pass them as function arguments, put them in
containers, et.
+ std: :move is necessary to make effective use of some standardJibrary types, such
unique_ptr.
+ Rialue 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.
Decision:
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 flle so that the reader does not have to look in
another file to find uses of the priate 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.
Pros:
+ 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 modem 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 tuning them off intemally makes it
harder to integrate with those libraries,
+ Exceptions are the only way for a constructor to fal. We can simulate this with a
factory function or an Init() method, but these require heap allocation or a new
“imalia” state, respectively,
+ Exceptions are really handy in testing frameworks,
hpsuigoogle.g iu fs uidecrpgul de hit
amsezeotr Google C++ Syle Guide
Cons:
+ When you add a throw statement to an existing function, you must examine all ofits
transitive callers. Either they must make at least the basic exception safety
‘uarantee, or they must never catch the exception and be happy with the program
terminating as a result. For instance, i €() calls g() calls h(), and h throws an
‘exception that f catches, g has to be careful orit may not clean up property
+ More generally, exceptions make the control low of programs dificult to evaluate by
looking at code: functions may retum in places you dontt expect. This causes
maintainability and debugging diffculties. You can minimize this cost va some rules
‘on how and where exceptions can be used, but at the cost of more that a developer
needs to know and understand.
+ Exceplion safety requires both RAll and diferent coding practices. Lots of supporting
machinery is needed to make writing correct exceplion-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's 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
+ Tuming on exceptions adds data to each binary produced, increasing compile time
(probably slightly) and possibly increasing address space pressure.
+ The availabilty of exceptions may encourage developers to throw them when they are
not appropriate or recover from them when its 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!
Decision:
(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-ree code. Because most existing C++ code
at Google is not prepared to deal with exceptions, it is comparatively dificult 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 altematives 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 dificult
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 ftom scratch,
This prohibition also applies to the exceptionelated 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 (RTT!)
Avoid using Run Time Type Information (RTT).
Definition:
hpsuigoogle.g iu fs uidecrpgul de hitezeotr
Google C++ Syle Guide
RTT allows a programmer to query the C++ class of an object at run time. This is done by
se of typeid or dynamic_cast.
Cons:
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.
Pros:
The standard altematives 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,
RTT can be uselul in some unit tests. For example, itis 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.
RTTis useful when considering multiple abstract objects. Consider
bool Base: :Equal(Base* other) = @;
bool Derived: :Equal(Base* other) (
Derived* that = dynamic_cast(other) ;
if (that == NULL)
return false;
Decision:
RTT 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 RTI in new code, If you find yourself needing to write code that behaves
diflerently based on the class of an object, consider one of the following altematives 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.
+ Ifthe work belongs outside the abject and instead in some processing code, consider
‘a double-dispatch solution, such as the Visitor design pattem. 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 altemative 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(tdata) == typeid(o2)) {
} else if (typeid(*data) == typeid(03)) {
Code such as this usually breaks when additional subclasses are added to the class
hierarchy. Moreover, when properties of a subclass change, itis diffcult to find and modify all
hpsuigoogle.g iu fs uidecrpgul de hit asezeotr
Google C++ Syle Guide
the affected code segments,
Do not hand-implement an RTTHike 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(double_value), or brace initialization for
conversion of arithmetic types Iké intéa y = int64{1} << 42. Donat 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)
Definition:
C++ introduced a different cast system ftom C that distinguishes the types of cast
operations,
Pros:
The problem with C casts is the ambiguity of the operation; sometimes you are doing a
conversion (e.g., (4nt)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.
Cons:
The C++-style cast syntax is verbose and cumbersome,
Decision:
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 RTI section for guidance on the use of dynamic_cast.
° Streams
Use streams where appropriate, and stick to "simple" usages.
Definition:
hpsuigoogle.g iu fs uidecrpgul de hit arsezeotr Google C++ Syle Guide
Streams are the standard (0 abstraction in C++, as exemplified by the standard header
. They are widely used in Google code, but only for debug logging and test
diagnostics.
Pros:
The << and >> stream operators provide an API for formatted VO 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 /O via std::cin, std::cout, std: :cern, and
std: :clog, The C APIs do as well, but are hampered by the need to manually buffer the
input,
Cons:
+ 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
prevous 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
builtin state, it can add new state variables and behaviors through a registration
system,
* Its diffcult 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
intemationalization, because it bakes word order into the code, and streams’ support
for localization is flawed.
+ The streams APIis 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 overtoads of << is extremely costly for the compiler, When used
penasively in a large code base, it can consume as much as 20% of the parsing and
‘semantic analysis time,
Decision:
Use streams only when they are the best tool for the job. This is typically the case when the
VO is ad-hoc, local, human-readable, and targeted at other developers rather than end-users,
Be consistent with the cade 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 V/O that faces extemal users or handles untrusted data. Instead, find
and use the appropriate templating libraries to handle issues like interiationalization,
localization, and security hardening.
you do use streams, avoid the stateful parts of the streams API (other than error state),
such as inbue(), 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 ofthat 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).
hpsuigoogle.g iu fs uidecrpgul de hit susezeotr Google C++ Syle Guide
°°Preincrement and Predecrement
Use prefix form (++i) of the increment and decrement operators with iterators and other
template objects.
Definition:
When a variable is incremented (+44 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).
Pros:
When the return value is ignored, the "pre" form (+4) is never less efficient than the "post"
form (i++), and is often more eficient. 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?
Cons:
The tradition developed, in C, of using post-increment when the expression value is not used,
especially in for loops. Some find postincrement easier to read, since the "subject" (i)
precedes the "verb" (++), just like in English.
Decision:
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.
Definition:
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
(eg. class Foo { int Bar(char c) const; };}
Pros:
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 funetions 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.
Cons:
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.
hpsuigoogle.g iu fs uidecrpgul de hit sansezeotr
Google C++ Syle Guide
Decision:
const \ariables, 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:
+ Ifa function guarantees that it wll 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 i'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 frst, 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.
Definition:
‘Some variables can be declared constexpr to indicate the variables are true constants, i.
fixed at compilation/link time. Some functions and constructors can be declared constexpr
which enables them to be used in defining a constexpr variable.
Pros:
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
funetion calls,
Cons:
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.
Decision:
hpsuigoogle.g iu fs uidecrpgul de hit sas