野外求生夫妻挡之艾图:Google C++ Style Guide
来源:百度文库 编辑:九乡新闻网 时间:2024/04/29 16:20:35
Google C++ Style Guide
Revision 3.188
Benjy WeinbergerCraig Silverstein
Gregory Eitzmann
Mark Mentovai
Tashana Landray
Each style point has a summary for which additional information is availableby toggling the accompanying arrow button that looks this way:▽.You may toggle all summaries with the big arrow button:
▽Toggle all summariesTable of Contents Header Files The #define Guard Header File Dependencies Inline Functions The -inl.h Files Function Parameter Ordering Names and Order of Includes Scoping Namespaces Nested Classes Nonmember, Static Member, and Global Functions Local Variables Static and Global Variables Classes Doing Work in Constructors Default Constructors Explicit Constructors Copy Constructors Structs vs. Classes Inheritance Multiple Inheritance Interfaces Operator Overloading Access Control Declaration Order Write Short Functions Google-Specific Magic Smart Pointers cpplint Other C++ Features Reference Arguments Function Overloading Default Arguments Variable-Length Arrays and alloca() Friends Exceptions Run-Time Type Information (RTTI) Casting Streams Preincrement and Predecrement Use of const Integer Types 64-bit Portability Preprocessor Macros 0 and NULL sizeof Boost C++0x Naming General Naming Rules File Names Type Names Variable Names Constant Names Function Names Namespace Names Enumerator Names Macro Names Exceptions to Naming Rules Comments Comment Style File Comments Class Comments Function Comments Variable Comments Implementation Comments Punctuation, Spelling and Grammar TODO Comments Deprecation Comments Formatting Line Length Non-ASCII Characters Spaces vs. Tabs Function Declarations and Definitions Function Calls Conditionals Loops and Switch Statements Pointer and Reference Expressions Boolean Expressions Return Values Variable and Array Initialization Preprocessor Directives Class Format Constructor Initializer Lists Namespace Formatting Horizontal Whitespace Vertical Whitespace Exceptions to the Rules Existing Non-conformant Code Windows CodeImportant Note
Displaying Hidden Details in this Guide
link▽This style guide contains many details that are initiallyhidden from view. They are marked by the triangle icon, which yousee here on your left. Click it now.You should see "Hooray" appear below.Hooray! Now you know you can expand points to get moredetails. Alternatively, there's an "expand all" at thetop of this document.
Background
C++ is the main development languageused by many of Google's open-sourceprojects.As every C++ programmer knows, the language has many powerful features,but this power brings with it complexity, which in turn can make codemore bug-prone and harder to read and maintain.
The goal of this guide is to manage this complexity by describingin detail the dos and don'ts of writing C++code. These rules exist tokeepthecode base manageable while still allowing coders to use C++ languagefeatures productively.
Style, also known as readability, is what we call theconventions that govern our C++ code. The term Style is a bit of amisnomer, since these conventions cover far more than just sourcefile formatting.
One way in which we keep the code base manageable is by enforcingconsistency.It is very important that anyprogrammerbe able to look at another's code and quickly understand it.Maintaining a uniform style and following conventions means that we canmore easily use "pattern-matching" to infer what various symbols areand what invariants are true about them. Creating common, requiredidioms and patterns makes code much easier to understand. In somecases there might be good arguments for changing certain stylerules, but we nonetheless keep things as they are in order topreserve consistency.
Another issue this guide addresses is that of C++ feature bloat.C++ is a huge language with many advanced features. In some caseswe constrain, or even ban, use of certain features. We do this tokeep code simple and to avoid the various common errors andproblems that these features can cause. This guide lists thesefeatures and explains why their use is restricted.
Open-source projects developed by Googleconform to the requirements in this guide.
Note that this guide is not a C++ tutorial: we assume that thereader is familiar with the language.
Header Files
In general, every .cc
file should have an associated.h
file. There are some common exceptions, such asunittestsand small .cc
files containing just a main()
function.
Correct use of header files can make a huge difference to thereadability, size and performance of your code.
The following rules will guide you through the various pitfalls ofusing header files.
The #define Guard
link▽All header files should have#define
guards toprevent multiple inclusion. The format of the symbol nameshould be _ _ _H_
.To guarantee uniqueness, they should be based on the full pathin a project's source tree. For example, the filefoo/src/bar/baz.h
in project foo
shouldhave the following guard:
#ifndef FOO_BAR_BAZ_H_#define FOO_BAR_BAZ_H_...#endif // FOO_BAR_BAZ_H_
Header File Dependencies
link▽Don't use an#include
when a forward declarationwould suffice.When you include a header file you introduce a dependency thatwill cause your code to be recompiled whenever the header filechanges. If your header file includes other header files, anychange to those files will cause any code that includes yourheader to be recompiled. Therefore, we prefer to minimizeincludes, particularly includes of header files in otherheader files.
You can significantly reduce the number of header files youneed to include in your own header files by using forwarddeclarations. For example, if your header file uses theFile
class in ways that do not require access tothe declaration of the File
class, your headerfile can just forward declare class File;
insteadof having to #include "file/base/file.h"
.
How can we use a class Foo
in a header filewithout access to its definition?
- We can declare data members of type
Foo*
orFoo&
. - We can declare (but not define) functions with arguments, and/or return values, of type
Foo
. (One exception is if an argumentFoo
orconst Foo&
has a non-explicit
, one-argument constructor, in which case we need the full definition to support automatic type conversion.) - We can declare static data members of type
Foo
. This is because static data members are defined outside the class definition.
On the other hand, you must include the header file forFoo
if your class subclasses Foo
orhas a data member of type Foo
.
Sometimes it makes sense to have pointer (or better,scoped_ptr
)members instead of object members. However, this complicates codereadability and imposes a performance penalty, so avoid doingthis transformation if the only purpose is to minimize includesin header files.
Of course, .cc
files typically do require thedefinitions of the classes they use, and usually have toinclude several header files.
Note:If you use a symbol Foo
in your source file, youshould bring in a definition for Foo
yourself,either via an #include or via a forward declaration. Do notdepend on the symbol being brought in transitively via headersnot directly included. One exception is if Foo
is used in myfile.cc
, it's ok to #include (orforward-declare) Foo
in myfile.h
,instead of myfile.cc
.
Inline Functions
link▽Define functions inline only when they are small, say, 10 linesor less.Definition: You can declare functions in a way that allows the compiler toexpand them inline rather than calling them through the usualfunction call mechanism.
Pros: Inlining a function can generate more efficient object code,as long as the inlined function is small. Feel free to inlineaccessors and mutators, and other short, performance-criticalfunctions.
Cons: Overuse of inlining can actually make programs slower.Depending on a function's size, inlining it can cause the codesize to increase or decrease. Inlining a very small accessorfunction will usually decrease code size while inlining a verylarge function can dramatically increase code size. On modernprocessors smaller code usually runs faster due to better useof the instruction cache.
Decision:
A decent rule of thumb is to not inline a function if it ismore than 10 lines long. Beware of destructors, which areoften longer than they appear because of implicit member-and base-destructor calls!
Another useful rule of thumb: it's typically not costeffective to inline functions with loops or switchstatements (unless, in the common case, the loop or switchstatement is never executed).
It is important to know that functions are not alwaysinlined 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 mainreason for making a virtual function inline is to place itsdefinition in the class, either for convenience or todocument its behavior, e.g., for accessors and mutators.
The -inl.h Files
link▽You may use file names with a-inl.h
suffix to definecomplex inline functions when needed.The definition of an inline function needs to be in a headerfile, so that the compiler has the definition available forinlining at the call sites. However, implementation codeproperly belongs in .cc
files, and we do not liketo have much actual code in .h
files unless thereis a readability or performance advantage.
If an inline function definition is short, with very little,if any, logic in it, you should put the code in your.h
file. For example, accessors and mutatorsshould certainly be inside a class definition. More complexinline functions may also be put in a .h
file forthe convenience of the implementer and callers, though if thismakes the .h
file too unwieldy you can insteadput that code in a separate -inl.h
file.This separates the implementation from the class definition,while still allowing the implementation to be included wherenecessary.
Another use of -inl.h
files is for definitions offunction templates. This can be used to keep your templatedefinitions easy to read.
Do not forget that a -inl.h
file requires a#define
guard justlike any other header file.
Function Parameter Ordering
link▽When defining a function, parameter order is: inputs,then outputs.Parameters to C/C++ functions are either input to thefunction, output from the function, or both. Input parametersare usually values or const
references, while outputand input/output parameters will be non-const
pointers. When ordering function parameters, put all input-onlyparameters before any output parameters. In particular, do not addnew parameters to the end of the function just because they arenew; place new input-only parameters before the outputparameters.
This is not a hard-and-fast rule. Parameters that are bothinput and output (often classes/structs) muddy the waters,and, as always, consistency with related functions may requireyou to bend the rule.
Names and Order of Includes
link▽Use standard order for readability and to avoid hiddendependencies: C library, C++ library,other libraries'.h
, yourproject's.h
.All of a project's header files should belisted as descendants of the project's source directorywithout use of UNIX directory shortcuts .
(the currentdirectory) or ..
(the parent directory). Forexample,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 indir2/foo2.h
, order your includes asfollows:
-
dir2/foo2.h
(preferred location — see details below). - C system files.
- C++ system files.
- Other libraries'
.h
files. - Your project's
.h
files.
The preferred ordering reduces hidden dependencies. We wantevery header file to be compilable on its own. The easiestway to achieve this is to make sure that every one of them isthe first .h
file #include
d in some.cc
.
dir/foo.cc
anddir2/foo2.h
are often in the samedirectory (e.g. base/basictypes_test.cc
andbase/basictypes.h
), but can be in differentdirectories too.
Within each section it is nice to order the includesalphabetically.
For example, the includes ingoogle-awesome-project/src/foo/internal/fooserver.cc
might look like this:
#include "foo/public/fooserver.h" // Preferred location.#include#include #include #include #include "base/basictypes.h"#include "base/commandlineflags.h"#include "foo/public/bar.h"
Scoping
Namespaces
link▽Unnamed namespaces in.cc
files are encouraged. Withnamed namespaces, choose the name based on theproject, and possibly its path.Do not use a using-directive.Definition: Namespaces subdivide the global scope into distinct, namedscopes, and so are useful for preventing name collisions inthe global scope.
Pros:
Namespaces provide a (hierarchical) axis of naming, inaddition to the (also hierarchical) name axis provided byclasses.
For example, if two different projects have a classFoo
in the global scope, these symbols maycollide at compile time or at runtime. If each projectplaces their code in a namespace, project1::Foo
and project2::Foo
are now distinct symbols thatdo not collide.
Cons:
Namespaces can be confusing, because they provide anadditional (hierarchical) axis of naming, in addition to the(also hierarchical) name axis provided by classes.
Use of unnamed spaces in header files can easily causeviolations of the C++ One Definition Rule (ODR).
Decision:
Use namespaces according to the policy described below.
Unnamed Namespaces
- Unnamed namespaces are allowed and even encouraged in
.cc
files, to avoid runtime naming conflicts:namespace { // This is in a .cc file. // The content of a namespace is not indented enum { kUnused, kEOF, kError }; // Commonly used tokens. bool AtEof() { return pos_ == kEOF; } // Uses our namespace's EOF. } // namespace
However, file-scope declarations that are associated with a particular class may be declared in that class as types, static data members or static member functions rather than as members of an unnamed namespace. Terminate the unnamed namespace as shown, with a comment
// namespace
. - Do not use unnamed namespaces in
.h
files.
Named Namespaces
Named namespaces should be used as follows:
- 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
The typical
.cc
file might have more complex detail, including the need to reference classes in other namespaces.#include "a.h" DEFINE_bool(someflag, false, "dummy flag"); class C; // Forward declaration of class C in the global namespace. namespace a { class A; } // Forward declaration of a::A. namespace b { ...code for b... // Code goes against the left margin. } // namespace b
- Do not declare anything in namespace
std
, not even 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;
- You may use a using-declaration anywhere in a
.cc
file, and in functions, methods or classes in.h
files.// OK in .cc files. // Must be in a function, method or class in .h files. using ::foo::bar;
- Namespace aliases are allowed anywhere in a
.cc
file, anywhere inside the named namespace that wraps an entire.h
file, and in functions and methods.// Shorten access to some commonly used names in .cc files. namespace fbz = ::foo::bar::baz; // Shorten access to some commonly used names (in a .h file). namespace librarian { // The following alias is available to all files including // this header (in namespace librarian): // alias names should therefore be chosen consistently // within a project. namespace pd_s = ::pipeline_diagnostics::sidetable; inline void my_inline_function() { // namespace alias local to a function (or method). namespace fbz = ::foo::bar::baz; ... } } // namespace librarian
Note that an alias in a .h file is visible to everyone #including that file, so public headers (those available outside a project) and headers transitively #included by them, should avoid defining aliases, as part of the general goal of keeping public APIs as small as possible.
Nested Classes
link▽Although you may use public nested classes when they are part ofan interface, consider a namespace tokeep declarations out of the global scope.Definition: A class can define another class within it; this is alsocalled a member class.
class Foo {private:// Bar is a member class, nested within Foo.class Bar {...};};
Pros: This is useful when the nested (or member) class is only usedby the enclosing class; making it a member puts it in theenclosing class scope rather than polluting the outer scopewith the class name. Nested classes can be forward declaredwithin the enclosing class and then defined in the.cc
file to avoid including the nested classdefinition in the enclosing class declaration, since thenested class definition is usually only relevant to theimplementation.
Cons: Nested classes can be forward-declared only within thedefinition of the enclosing class. Thus, any header filemanipulating a Foo::Bar*
pointer will have toinclude the full class declaration for Foo
.
Decision: Do not make nested classes public unless they are actuallypart of the interface, e.g., a class that holds a set ofoptions for some method.
Nonmember, Static Member, and Global Functions
link▽Prefer nonmember functions within a namespace or static memberfunctions to global functions; use completely global functionsrarely.Pros: Nonmember and static member functions can be useful in somesituations. Putting nonmember functions in a namespace avoidspolluting the global namespace.
Cons: Nonmember and static member functions may make more sense asmembers of a new class, especially if they access externalresources or have significant dependencies.
Decision:
Sometimes it is useful, or even necessary, to define afunction not bound to a class instance. Such a function canbe 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 thancreating classes only to group static member functions whichdo not share static data, usenamespaces instead.
Functions defined in the same compilation unit as productionclasses may introduce unnecessary coupling and link-timedependencies when directly called from other compilationunits; static member functions are particularly susceptibleto this. Consider extracting a new class, or placing thefunctions in a namespace possibly in a separate library.
If you must define a nonmember function and it is onlyneeded in its .cc
file, use an unnamednamespace or static
linkage (eg static int Foo() {...}
) to limitits scope.
Local Variables
link▽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 aspossible, and as close to the first use as possible. Thismakes it easier for the reader to find the declaration and seewhat type the variable is and what it was initialized to. Inparticular, initialization should be used instead ofdeclaration and assignment, e.g.
int i;i = f(); // Bad -- initialization separate from declaration.
int j = g(); // Good -- declaration has initialization.
Note that gcc implements for (int i = 0; i< 10; ++i)
correctly (the scope of i
isonly the scope of the for
loop), so you can thenreuse i
in another for
loop in thesame scope. It also correctly scopes declarations inif
and while
statements, e.g.
while (const char* p = strchr(str, '/')) str = p + 1;
There is one caveat: if the variable is an object, itsconstructor is invoked every time it enters scope and iscreated, and its destructor is invoked every time it goesout of scope.
// Inefficient implementation:for (int i = 0; i < 1000000; ++i) {Foo f; // My ctor and dtor get called 1000000 times each.f.DoSomething(i);}
It may be more efficient to declare such a variable used in aloop 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
link▽Static or global variables of class type are forbidden: they causehard-to-find bugs due to indeterminate order of construction anddestruction.Objects with static storage duration, including global variables,static variables, static class member variables, and function staticvariables, must be Plain Old Data (POD): only ints, chars, floats, orpointers, or arrays/structs of POD.
The order in which class constructors and initializers forstatic variables are called is only partially specified in C++ and caneven change from build to build, which can cause bugs that are difficultto find. Therefore in addition to banning globals of class type, we donot allow static POD variables to be initialized with the result of afunction, unless that function (such as getenv(), or getpid()) does notitself depend on any other globals.
Likewise, the order in which destructors are called is defined to be thereverse of the order in which the constructors were called. Sinceconstructor order is indeterminate, so is destructor order.For example, at program-end time a static variable might havebeen 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 thatcontains a reference to that string.
As a result we only allow static variables to contain POD data. Thisrule completely disallows vector
(use C arrays instead), orstring
(use const char []
).
If you need a static or global variable of a class type, considerinitializing a pointer (which will never be freed), from either yourmain() function or from pthread_once(). Note that this must be a rawpointer, not a "smart" pointer, since the smart pointer's destructorwill have the order-of-destructor issue that we are trying to avoid.
Classes
Classes are the fundamental unit of code in C++. Naturally, we usethem extensively. This section lists the main dos and don'ts youshould follow when writing a class.Doing Work in Constructors
link▽In general, constructors should merely set member variables to theirinitial values. Any complex initialization should go in an explicitInit()
method.Definition: It is possible to perform initialization in the body of theconstructor.
Pros: Convenience in typing. No need to worry about whether theclass has been initialized or not.
Cons: The problems with doing work in constructors are:
- There is no easy way for constructors to signal errors, short of using exceptions (which are forbidden).
- If the work fails, we now have an object whose initialization code failed, so it may be an indeterminate state.
- 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.
- If someone creates a global variable of this type (which is against the rules, but still), the constructor code will be called before
main()
, possibly breaking some implicit assumptions in the constructor code. For instance, gflags will not yet have been initialized.
Decision: If your object requires non-trivial initialization, considerhaving an explicit Init()
method. In particular,constructors should not call virtual functions, attempt to raiseerrors, access potentially uninitialized global variables, etc.
Default Constructors
link▽You must define a default constructor if your class definesmember variables and has no other constructors. Otherwise thecompiler will do it for you, badly.Definition: The default constructor is called when we new
aclass object with no arguments. It is always called whencalling new[]
(for arrays).
Pros: Initializing structures by default, to hold "impossible"values, makes debugging much easier.
Cons: Extra work for you, the code writer.
Decision:
If your class defines member variables and has no otherconstructors you must define a default constructor (one thattakes no arguments). It should preferably initialize theobject in such a way that its internal state is consistentand valid.
The reason for this is that if you have no otherconstructors and do not define a default constructor, thecompiler will generate one for you. This compilergenerated constructor may not initialize your objectsensibly.
If your class inherits from an existing class but you add nonew member variables, you are not required to have a defaultconstructor.
Explicit Constructors
link▽Use the C++ keywordexplicit
for constructors withone argument.Definition: Normally, if a constructor takes one argument, it can be usedas a conversion. For instance, if you defineFoo::Foo(string name)
and then pass a string to afunction that expects a Foo
, the constructor willbe called to convert the string into a Foo
andwill pass the Foo
to your function for you. Thiscan be convenient but is also a source of trouble when thingsget converted and new objects created without you meaning themto. Declaring a constructor explicit
prevents itfrom being invoked implicitly as a conversion.
Pros: Avoids undesirable conversions.
Cons: None.
Decision:
We require all single argument constructors to beexplicit. Always put explicit
in front ofone-argument constructors in the class definition:explicit Foo(string name);
The exception is copy constructors, which, in the rarecases when we allow them, should probably not beexplicit
.Classes that are intended to betransparent wrappers around other classes are alsoexceptions.Such exceptions should be clearly marked with comments.
Copy Constructors
link▽Provide a copy constructor and assignment operator only when necessary.Otherwise, disable them withDISALLOW_COPY_AND_ASSIGN
.Definition: The copy constructor and assignment operator are used to create copiesof objects. The copy constructor is implicitly invoked by thecompiler in some situations, e.g. passing objects by value.
Pros: Copy constructors make it easy to copy objects. STLcontainers require that all contents be copyable andassignable. Copy constructors can be more efficient thanCopyFrom()
-style workarounds because they combineconstruction with copying, the compiler can elide them in somecontexts, and they make it easier to avoid heap allocation.
Cons: Implicit copying of objects in C++ is a rich source of bugsand of performance problems. It also reduces readability, asit becomes hard to track which objects are being passed aroundby value as opposed to by reference, and therefore wherechanges to an object are reflected.
Decision:
Few classes need to be copyable. Most should have neither acopy constructor nor an assignment operator. In many situations,a pointer or reference will work just as well as a copied value,with better performance. For example, you can pass functionparameters by reference or pointer instead of by value, and you canstore pointers rather than objects in an STL container.
If your class needs to be copyable, prefer providing a copy method,such as CopyFrom()
or Clone()
, rather thana copy constructor, because such methods cannot be invokedimplicitly. If a copy method is insufficient in your situation(e.g. for performance reasons, or because your class needs to bestored by value in an STL container), provide both a copyconstructor and assignment operator.
If your class does not need a copy constructor or assignmentoperator, you must explicitly disable them.To do so, add dummy declarations for the copy constructor andassignment operator in the private:
section of yourclass, but do not provide any corresponding definition (so thatany attempt to use them results in a link error).
For convenience, a DISALLOW_COPY_AND_ASSIGN
macrocan be used:
// A macro to disallow the copy constructor and operator= functions// This should be used in the private: declarations for a class#define DISALLOW_COPY_AND_ASSIGN(TypeName) TypeName(const TypeName&); void operator=(const TypeName&)
Then, in class Foo
:
class Foo {public:Foo(int f);~Foo();private:DISALLOW_COPY_AND_ASSIGN(Foo);};
Structs vs. Classes
link▽Use astruct
only for passive objects that carry data;everything else is a class
.The struct
and class
keywords behavealmost identically in C++. We add our own semantic meaningsto each keyword, so you should use the appropriate keyword forthe data-type you're defining.
structs
should be used for passive objects that carrydata, and may have associated constants, but lack any functionalityother than access/setting the data members. Theaccessing/setting of fields is done by directly accessing thefields rather than through method invocations. Methods shouldnot provide behavior but should only be used to set up thedata members, e.g., constructor, destructor,Initialize()
, Reset()
,Validate()
.
If more functionality is required, a class
is moreappropriate. 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 havedifferent naming rules.
Inheritance
link▽Composition is often more appropriate than inheritance. Whenusing inheritance, make itpublic
.Definition: When a sub-class inherits from a base class, it includes thedefinitions of all the data and operations that the parentbase class defines. In practice, inheritance is used in twomajor ways in C++: implementation inheritance, in whichactual code is inherited by the child, and interface inheritance, in which onlymethod names are inherited.
Pros: Implementation inheritance reduces code size by re-using thebase class code as it specializes an existing type. Becauseinheritance is a compile-time declaration, you and thecompiler can understand the operation and detect errors.Interface inheritance can be used to programmatically enforcethat a class expose a particular API. Again, the compilercan detect errors, in this case, when a class does not definea necessary method of the API.
Cons: For implementation inheritance, because the code implementinga sub-class is spread between the base and the sub-class, itcan be more difficult to understand an implementation. Thesub-class cannot override functions that are not virtual, sothe sub-class cannot change implementation. The base classmay also define some data members, so that specifies physicallayout of the base class.
Decision:
All inheritance should be public
. If you want todo private inheritance, you should be including an instance ofthe base class as a member instead.
Do not overuse implementation inheritance. Composition isoften more appropriate. Try to restrict use of inheritanceto the "is-a" case: Bar
subclassesFoo
if it can reasonably be said thatBar
"is a kind of" Foo
.
Make your destructor virtual
if necessary. Ifyour class has virtual methods, its destructorshould be virtual.
Limit the use of protected
to those memberfunctions that might need to be accessed from subclasses.Note that data members shouldbe private.
When redefining an inherited virtual function, explicitlydeclare it virtual
in the declaration of thederived class. Rationale: If virtual
isomitted, the reader has to check all ancestors of theclass in question to determine if the function is virtualor not.
Multiple Inheritance
link▽Only very rarely is multiple implementation inheritance actuallyuseful. We allow multiple inheritance only when at most one ofthe base classes has an implementation; all other base classesmust be pure interface classes taggedwith theInterface
suffix.Definition: Multiple inheritance allows a sub-class to have more than onebase class. We distinguish between base classes that arepure interfaces and those that have animplementation.
Pros: Multiple implementation inheritance may let you re-use even more codethan single inheritance (see Inheritance).
Cons: Only very rarely is multiple implementationinheritance actually useful. When multiple implementationinheritance seems like the solution, you can usually find adifferent, more explicit, and cleaner solution.
Decision: Multiple inheritance is allowed only when all superclasses, with thepossible exception of the first one, are pureinterfaces. In order to ensure that they remain pure interfaces,they must end with the Interface
suffix.
Note:There is an exception to thisrule on Windows.
Interfaces
link▽Classes that satisfy certain conditions are allowed, but not required, toend with anInterface
suffix.Definition:
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 instantiatedbecause of the pure virtual method(s) it declares. To makesure all implementations of the interface can be destroyedcorrectly, they must also declare a virtual destructor (inan exception to the first rule, this should not be pure). SeeStroustrup, The C++ Programming Language, 3rdedition, section 12.4 for details.
Pros: Tagging a class with the Interface
suffix letsothers know that they must not add implemented methods or nonstatic data members. This is particularly important in the case ofmultiple inheritance.Additionally, the interface concept is already well-understood byJava programmers.
Cons: The Interface
suffix lengthens the class name, whichcan make it harder to read and understand. Also, the interfaceproperty may be considered an implementation detail that shouldn'tbe exposed to clients.
Decision: A class may end with Interface
only if it meets theabove requirements. We do not require the converse, however:classes that meet the above requirements are not required to endwith Interface
.
Operator Overloading
link▽Do not overload operators except in rare, special circumstances.Definition: A class can define that operators such as +
and/
operate on the class as if it were a built-intype.
Pros: Can make code appear more intuitive because a class willbehave in the same way as built-in types (such asint
). Overloaded operators are more playfulnames for functions that are less-colorfully named, such asEquals()
or Add()
. For sometemplate functions to work correctly, you may need to defineoperators.
Cons: While operator overloading can make code more intuitive, ithas several drawbacks:
- It can fool our intuition into thinking that expensive operations are cheap, built-in operations.
- It is much harder to find the call sites for overloaded operators. Searching for
Equals()
is much easier than searching for relevant invocations of==
. - Some operators work on pointers too, making it easy to introduce bugs.
Foo + 4
may do one thing, while&Foo + 4
does something totally different. The compiler does not complain for either of these, making this very hard to debug.
operator&
, itcannot safely be forward-declared.
Decision:
In general, do not overload operators. The assignment operator(operator=
), in particular, is insidious andshould be avoided. You can define functions likeEquals()
and CopyFrom()
if youneed them. Likewise, avoid the dangerousunary operator&
at all costs, if there'sany possibility the class might be forward-declared.
However, there may be rare cases where you need to overloadan operator to interoperate with templates or "standard" C++classes (such as operator<<(ostream&, constT&)
for logging). These are acceptable if fullyjustified, but you should try to avoid these wheneverpossible. In particular, do not overload operator==
or operator<
just so that your class can beused as a key in an STL container; instead, you shouldcreate equality and comparison functor types when declaringthe container.
Some of the STL algorithms do require you to overloadoperator==
, and you may do so in these cases,provided you document why.
See also Copy Constructorsand FunctionOverloading.
Access Control
link▽Make data membersprivate
, and provideaccess to them through accessor functions as needed (fortechnical reasons, we allow data members of a test fixture classto be protected
when usingGoogle Test). Typically a variable would becalled foo_
and the accessor functionfoo()
. You may also want a mutator functionset_foo()
.Exception: static const
data members (typicallycalled kFoo
) need not be private
.The definitions of accessors are usually inlined in the headerfile.
See also Inheritance and Function Names.
Declaration Order
link▽Use the specified order of declarations within a class:public:
before private:
, methodsbefore data members (variables), etc.Your class definition should start with its public:
section, followed by its protected:
section andthen its private:
section. If any of these sectionsare empty, omit them.
Within each section, the declarations generally should be inthe following order:
- Typedefs and Enums
- Constants (
static const
data members) - Constructors
- Destructor
- Methods, including static methods
- Data Members (except
static const
data members)
Friend declarations should always be in the private section, andthe DISALLOW_COPY_AND_ASSIGN
macro invocationshould be at the end of the private:
section. Itshould be the last thing in the class. See Copy Constructors.
Method definitions in the corresponding .cc
fileshould be the same as the declaration order, as much as possible.
Do not put large method definitions inline in the classdefinition. Usually, only trivial or performance-critical,and very short, methods may be defined inline. See Inline Functions for moredetails.
Write Short Functions
link▽Prefer small and focused functions.We recognize that long functions are sometimes appropriate, sono hard limit is placed on functions length. If a functionexceeds about 40 lines, think about whether it can be brokenup without harming the structure of the program.
Even if your long function works perfectly now, someonemodifying it in a few months may add new behavior. This couldresult in bugs that are hard to find. Keeping your functionsshort and simple makes it easier for other people to read andmodify your code.
You could find long and complicated functions when workingwithsomecode. Do not be intimidated by modifying existingcode: if working with such a function proves to be difficult,you find that errors are hard to debug, or you want to use apiece of it in several different contexts, consider breakingup the function into smaller and more manageable pieces.
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 fromwhat you see elsewhere.
Smart Pointers
link▽If you actually need pointer semantics,scoped_ptr
is great. You should only use std::tr1::shared_ptr
with a non-const referent when it is truly necessary to share ownershipof an object (e.g. inside an STL container). You should never useauto_ptr
.Definition: "Smart" pointers are objects that act like pointers, but automatemanagement of the underlying memory.
Pros: Smart pointers are extremely useful for preventing memory leaks, andare essential for writing exception-safe code. They also formalizeand document the ownership of dynamically allocated memory.
Cons: We prefer designs in which objects have single, fixed owners. Smartpointers which enable sharing or transfer of ownership can act as atempting alternative to a careful design of ownership semantics,leading to confusing code and even bugs in which memory is neverdeleted. The semantics of smart pointers (especiallyauto_ptr
) can be nonobvious and confusing. Theexception-safety benefits of smart pointers are not decisive, sincewe do not allow exceptions.
Decision:
scoped_ptr
- Straightforward and risk-free. Use wherever appropriate.
auto_ptr
- Confusing and bug-prone ownership-transfer semantics. Do not use.
shared_ptr
- Safe with const referents (i.e.
shared_ptr
). Reference-counted pointers with non-const referentscan occasionally be the best design, but try to rewrite with singleowners where possible.
cpplint
link▽Usecpplint.py
to detect style errors.cpplint.py
is a tool that reads a source file andidentifies many style errors. It is not perfect, and has both falsepositives and false negatives, but it is still a valuable tool. Falsepositives can be ignored by putting // NOLINT
atthe end of the line.
Some projects have instructions on how to run cpplint.py
from their project tools. If the project you are contributing to doesnot, you can download cpplint.py
separately.
Other C++ Features
Reference Arguments
link▽All parameters passed by reference must be labeledconst
.Definition: In C, if a function needs to modify a variable, theparameter must use a pointer, eg int foo(int*pval)
. In C++, the function can alternativelydeclare a reference parameter: int foo(int&val)
.
Pros: Defining a parameter as reference avoids ugly code like(*pval)++
. Necessary for some applications likecopy constructors. Makes it clear, unlike with pointers, thatNULL
is not a possible value.
Cons: References can be confusing, as they have value syntax butpointer semantics.
Decision:
Within function parameter lists all references must beconst
:
void Foo(const string &in, string *out);
In fact it is a very strong convention in Google code that inputarguments are values or const
references whileoutput arguments are pointers. Input parameters may beconst
pointers, but we never allownon-const
reference parameters.
One case when you might want an input parameter to be aconst
pointer is if you want to emphasize that theargument is not copied, so it must exist for the lifetime of theobject; it is usually best to document this in comments aswell. STL adapters such as bind2nd
andmem_fun
do not permit reference parameters, soyou must declare functions with pointer parameters in thesecases, too.
Function Overloading
link▽Use overloaded functions (including constructors) only if areader looking at a call site can get a good idea of what ishappening without having to first figure out exactly whichoverload is being called.Definition:
You may write a function that takes aconst string&
and overload it with another thattakes const char*
.
class MyClass {public:void Analyze(const string &text);void Analyze(const char *text, size_t textlen);};
Pros: Overloading can make code more intuitive by allowing anidentically-named function to take different arguments. Itmay be necessary for templatized code, and it can beconvenient for Visitors.
Cons: If a function is overloaded by the argument types alone, areader may have to understand C++'s complex matching rules inorder to tell what's going on. Also many people are confusedby the semantics of inheritance if a derived class overridesonly some of the variants of a function.
Decision: If you want to overload a function, consider qualifying thename with some information about the arguments, e.g.,AppendString()
, AppendInt()
ratherthan just Append()
.
Default Arguments
link▽We do not allow default function parameters, except ina few uncommon situations explained below.Pros: Often you have a function that uses lots of default values,but occasionally you want to override the defaults. Defaultparameters allow an easy way to do this without having todefine many functions for the rare exceptions.
Cons: People often figure out how to use anAPI by looking at existing code that uses it.Default parameters are more difficult to maintain becausecopy-and-paste from previous code may not reveal all theparameters. Copy-and-pasting of code segments can cause majorproblems when the default arguments are not appropriate forthe new code.
Decision:
Except as described below, we require all arguments to beexplicitly specified, to force programmers to consider the APIand the values they are passing for each argument rather thansilently accepting defaults they may not be aware of.
One specific exception is when default arguments are used tosimulate variable-length argument lists.
// Support up to 4 params by using a default empty AlphaNum.string StrCat(const AlphaNum &a,const AlphaNum &b = gEmptyAlphaNum,const AlphaNum &c = gEmptyAlphaNum,const AlphaNum &d = gEmptyAlphaNum);
Variable-Length Arrays and alloca()
link▽We do not allow variable-length arrays oralloca()
.Pros: Variable-length arrays have natural-looking syntax. Bothvariable-length arrays and alloca()
are veryefficient.
Cons: Variable-length arrays and alloca are not part of StandardC++. More importantly, they allocate a data-dependent amountof stack space that can trigger difficult-to-find memoryoverwriting bugs: "It ran fine on my machine, but diesmysteriously in production".
Decision: Use a safe allocator instead, such asscoped_ptr
/scoped_array
.
Friends
link▽We allow use offriend
classes and functions,within reason.Friends should usually be defined in the same file so that thereader does not have to look in another file to find uses ofthe private members of a class. A common use offriend
is to have a FooBuilder
classbe a friend of Foo
so that it can construct theinner state of Foo
correctly, without exposingthis state to the world. In some cases it may be useful tomake a unittest class a friend of the class it tests.
Friends extend, but do not break, the encapsulationboundary of a class. In some cases this is better than makinga member public when you want to give only one other classaccess to it. However, most classes should interact withother classes solely through their public members.
Exceptions
link▽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 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.
Cons:
- 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, iff()
callsg()
callsh()
, 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!
Decision:
On their face, the benefits of using exceptions outweigh thecosts, especially in new projects. However, for existing code,the introduction of exceptions has implications on all dependentcode. If exceptions can be propagated beyond a new project, italso becomes problematic to integrate the new project intoexisting exception-free code. Because most existing C++ code atGoogle is not prepared to deal with exceptions, it iscomparatively difficult to adopt new code that generatesexceptions.
Given that Google's existing code is not exception-tolerant, thecosts of using exceptions are somewhat greater than the costs ina new project. The conversion process would be slow anderror-prone. We don't believe that the available alternatives toexceptions, such as error codes and assertions, introduce asignificant burden.
Our advice against using exceptions is not predicated onphilosophical or moral grounds, but practical ones.Because we'd like to use our open-sourceprojects at Google and it's difficult to do so if those projectsuse exceptions, we need to advise against exceptions in Googleopen-source projects as well.Things would probably be different if we had to do it all overagain from scratch.
There is an exception to thisrule (no pun intended) for Windows code.
Run-Time Type Information (RTTI)
link▽We do not use Run Time Type Information (RTTI).Definition: RTTI allows a programmer to query the C++ class of anobject at run time.
Pros:
It is useful in some unittests. For example, it is useful intests of factory classes where the test has to verify that anewly created object has the expected dynamic type.
In rare circumstances, it is useful even outside oftests.
Cons: A query of type during run-time typically means adesign problem. If you need to know the type of anobject at runtime, that is often an indication thatyou should reconsider the design of your class.
Decision:
Do not use RTTI, except in unittests. If you find yourselfin need of writing code that behaves differently based onthe class of an object, consider one of the alternatives toquerying the type.
Virtual methods are the preferred way of executing differentcode paths depending on a specific subclass type. This putsthe work within the object itself.
If the work belongs outside the object and instead in someprocessing code, consider a double-dispatch solution, suchas the Visitor design pattern. This allows a facilityoutside the object itself to determine the type of classusing the built-in type system.
If you think you truly cannot use those ideas,you may use RTTI. But think twiceabout it. :-) Then think twice again.Do not hand-implement an RTTI-like workaround. The argumentsagainst RTTI apply just as much to workarounds like classhierarchies with type tags.
Casting
link▽Use C++ casts likestatic_cast<>()
. Do not useother cast formats like int y = (int)x;
orint y = int(x);
.Definition: C++ introduced a different cast system from C thatdistinguishes 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.,(int)3.5
) and sometimes you are doing acast (e.g., (int)"hello"
); C++ castsavoid this. Additionally C++ casts are more visible whensearching for them.
Cons: The syntax is nasty.
Decision:
Do not use C-style casts. Instead, use these C++-stylecasts.
- Use
static_cast
as the equivalent of a C-style cast that does value conversion, or when you need to explicitly up-cast a pointer from a class to its superclass. - Use
const_cast
to remove theconst
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. - Do not use
dynamic_cast
except in test code. If you need to know type information at runtime in this way outside of a unittest, you probably have a design flaw.
Streams
link▽Use streams only for logging.Definition: Streams are a replacement for printf()
andscanf()
.
Pros: With streams, you do not need to know the type of the objectyou are printing. You do not have problems with formatstrings not matching the argument list. (Though with gcc, youdo not have that problem with printf
either.) Streamshave automatic constructors and destructors that open and close therelevant files.
Cons: Streams make it difficult to do functionality likepread()
. Some formatting (particularly the commonformat string idiom %.*s
) is difficult if notimpossible to do efficiently using streams without usingprintf
-like hacks. Streams do not support operatorreordering (the %1s
directive), which is helpful forinternationalization.
Decision:
Do not use streams, except where required by a logging interface.Use printf
-like routines instead.
There are various pros and cons to using streams, but inthis case, as in many other cases, consistency trumps thedebate. Do not use streams in your code.
Extended Discussion
There has been debate on this issue, so this explains thereasoning in greater depth. Recall the Only One Wayguiding principle: we want to make sure that whenever wedo a certain type of I/O, the code looks the same in allthose places. Because of this, we do not want to allowusers to decide between using streams or usingprintf
plus Read/Write/etc. Instead, we shouldsettle on one or the other. We made an exception for loggingbecause it is a pretty specialized application, and forhistorical reasons.
Proponents of streams have argued that streams are the obviouschoice of the two, but the issue is not actually so clear. Forevery advantage of streams they point out, there is anequivalent disadvantage. The biggest advantage is thatyou do not need to know the type of the object to beprinting. This is a fair point. But, there is adownside: you can easily use the wrong type, and thecompiler will not warn you. It is easy to make thiskind of mistake without knowing when using streams.
cout << this; // Prints the addresscout << *this; // Prints the contents
The compiler does not generate an error because<<
has been overloaded. We discourageoverloading for just this reason.
Some say printf
formatting is ugly and hard toread, but streams are often no better. Consider the followingtwo fragments, both with the same typo. Which is easier todiscover?
cerr << "Error connecting to '" << foo->bar()->hostname.first<< ":" << foo->bar()->hostname.second << ": " << strerror(errno);fprintf(stderr, "Error connecting to '%s:%u: %s",foo->bar()->hostname.first, foo->bar()->hostname.second,strerror(errno));
And so on and so forth for any issue you might bring up.(You could argue, "Things would be better with the rightwrappers," but if it is true for one scheme, is it notalso true for the other? Also, remember the goal is tomake the language smaller, not add yet more machinery thatsomeone has to learn.)
Either path would yield different advantages anddisadvantages, and there is not a clearly superiorsolution. The simplicity doctrine mandates we settle onone of them though, and the majority decision was onprintf
+ read
/write
.
Preincrement and Predecrement
link▽Use prefix form (++i
) of the increment anddecrement operators with iterators and other template objects.Definition: When a variable is incremented (++i
ori++
) or decremented (--i
ori--
) and the value of the expression is not used,one must decide whether to preincrement (decrement) orpostincrement (decrement).
Pros: 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 isbecause post-increment (or decrement) requires a copy ofi
to be made, which is the value of theexpression. If i
is an iterator or othernon-scalar type, copying i
could be expensive.Since the two types of increment behave the same when thevalue is ignored, why not just always pre-increment?
Cons: The tradition developed, in C, of using post-increment whenthe 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.
Decision: For simple scalar (non-object) values there is no reason toprefer one form and we allow either. For iterators and othertemplate types, use pre-increment.
Use of const
link▽We strongly recommend that you useconst
wheneverit makes sense to do so.Definition: Declared variables and parameters can be preceded by thekeyword const
to indicate the variables are notchanged (e.g., const int foo
). Class functionscan have the const
qualifier to indicate thefunction does not change the state of the class membervariables (e.g., 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 convincethemselves of program correctness because they know thefunctions they call are limited in how they can modify yourvariables. Helps people know what functions are safe to usewithout 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 aconst_cast
). This can be a particular problemwhen calling library functions.
Decision:
const
variables, data members, methods andarguments add a level of compile-time type checking; itis better to detect errors as soon as possible.Therefore we strongly recommend that you useconst
whenever it makes sense to do so:
- If a function does not modify an argument passed by reference or by pointer, that argument should be
const
. - Declare methods to be
const
whenever possible. Accessors should almost always beconst
. 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.
However, do not go crazy with const
. Something likeconst int * const * const x;
is likelyoverkill, even if it accurately describes how const x is.Focus on what's really useful to know: in this case,const int** x
is probably sufficient.
The mutable
keyword is allowed but is unsafewhen used with threads, so thread safety should be carefullyconsidered first.
Where to put the const
Some people favor the form int const *foo
toconst int* foo
. They argue that this is morereadable because it's more consistent: it keeps the rulethat const
always follows the object it'sdescribing. However, this consistency argument doesn'tapply in this case, because the "don't go crazy" dictumeliminates most of the uses you'd have to be consistent with.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 aroundyou!
Integer Types
link▽Of the built-in C++ integer types, the only one usedisint
. If a program needs a variable of a differentsize, usea precise-width integer type from
, such as int16_t
.Definition: C++ does not specify the sizes of its integer types. Typicallypeople assume that short
is 16 bits,int
is 32 bits, long
is 32 bits andlong long
is 64 bits.
Pros: Uniformity of declaration.
Cons: The sizes of integral types in C++ can vary based on compilerand architecture.
Decision:
definestypes like int16_t
, uint32_t
,int64_t
, etc.You should always use those in preference toshort
, unsigned long long
and thelike, when you need a guarantee on the size of an integer.Of the C integer types, only int
should beused. When appropriate, you are welcome to use standardtypes like size_t
and ptrdiff_t
.
We use int
very often, for integers we know are notgoing to be too big, e.g., loop counters. Use plain oldint
for such things. You should assume that anint
isat least 32 bits,but don't assume that it has more than 32 bits.If you need a 64-bit integer type, useint64_t
oruint64_t
.
For integers we know can be "big",useint64_t
.
You should not use the unsigned integer types such asuint32_t
,unless the quantity you are representing is really a bit patternrather than a number, or unless you need definedtwos-complement overflow. In particular, do not use unsignedtypes to say a number will never be negative. Instead, useassertions for this.
On Unsigned Integers
Some people, including some textbook authors, recommendusing unsigned types to represent numbers that are nevernegative. This is intended as a form of self-documentation.However, in C, the advantages of such documentation areoutweighed 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 noticethis bug and warn you, but often it will not. Equally badbugs can occur when comparing signed and unsignedvariables. Basically, C's type-promotion scheme causesunsigned types to behave differently than one might expect.
So, document that a variable is non-negative usingassertions.Don't use an unsigned type.
64-bit Portability
link▽Code should be 64-bit and 32-bit friendly. Bear in mind problems ofprinting, 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 fileinttypes.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%zd
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. 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 asprintf("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;
- If you really need different code on 32-bit and 64-bit systems, use
#ifdef _LP64
to choose between the code variants. (But please avoid this if possible, and keep any such changes localized.)
Preprocessor Macros
link▽Be very cautious with macros. Prefer inline functions, enums,andconst
variables to macros.Macros mean that the code you see is not the same as the codethe compiler sees. This can introduce unexpected behavior,especially since macros have global scope.
Luckily, macros are not nearly as necessary in C++ as they arein C. Instead of using a macro to inline performance-criticalcode, use an inline function. Instead of using a macro tostore a constant, use a const
variable. Instead ofusing a macro to "abbreviate" a long variable name, use areference. 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 ofheader files). It makes testing much more difficult.
Macros can do things these other techniques cannot, and you dosee them in the codebase, especially in the lower-levellibraries. And some of their special features (likestringifying, concatenation, and so forth) are not availablethrough the language proper. But before using a macro,consider carefully whether there's a non-macro way to achievethe same result.
The following usage pattern will avoid many problems withmacros; 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.
0 and NULL
link▽Use0
for integers, 0.0
for reals,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
and NULL
. Bjarne Stroustrup prefers an unadorned0
. We prefer NULL
because it looks like apointer. In fact, some C++ compilers, such as gcc 4.1.0, provide specialdefinitions of NULL
which enable them to give usefulwarnings, 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
link▽Usesizeof(varname)
instead ofsizeof(type)
whenever possible.Use sizeof(varname)
because it will updateappropriately if the type of the variable changes.sizeof(type)
may make sense in some cases,but should generally be avoided because it can fall out of sync ifthe variable's type changes.
Struct data;memset(&data, 0, sizeof(data));
memset(&data, 0, sizeof(Struct));
Boost
link▽Use only approved libraries from the Boost library collection.Definition: The Boost library collection isa popular collection of peer-reviewed, free, open-source C++ libraries.
Pros: Boost code is generally very high-quality, is widely portable, and fillsmany important gaps in the C++ standard library, such as type traits,better binders, and better smart pointers. It also provides animplementation of the TR1 extension to the standard library.
Cons: Some Boost libraries encourage coding practices which can hamperreadability, such as metaprogramming and other advanced templatetechniques, and an excessively "functional" style of programming.
Decision:
In order to maintain a high level of readability for all contributorswho might read and maintain code, we only allow an approved subset ofBoost features. Currently, the following libraries are permitted:- Call Traits from
boost/call_traits.hpp
- Compressed Pair from
boost/compressed_pair.hpp
- Pointer Container from
boost/ptr_container
except serialization and wrappers for containers not in the C++03 standard (ptr_circular_buffer.hpp
andptr_unordered*
) - Array from
boost/array.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/*
andboost/graph/distributed/*
). - Property Map from
boost/property_map
, except parallel/distributed property maps (boost/property_map/parallel/*
). - The part of Iterator that deals with defining iterators:
boost/iterator/iterator_adaptor.hpp
,boost/iterator/iterator_facade.hpp
, andboost/function_output_iterator.hpp
C++0x
link▽Use only approved libraries and language extensions from C++0x.Currently, none are approved.Definition: C++0x is the next ISO C++ standard, currently infinalcommittee draft form. It containssignificantchanges both to the language and libraries.
Pros: We expect that C++0x will become the next standard, and eventually willbe supported by most C++ compilers. It standardizes some common C++extensions that we use already, allows shorthands for some operations,and has some safety improvements.
Cons:
The C++0x standard is substantialy more complex than its predecessor(1,300 pages versus 800 pages), and isunfamilar to many developers. The long-term effects of somefeatures on code readability and maintenance are unknown. We cannotpredict when its various features will be implemented uniformly bytools that may be of interest (gcc, icc, clang, Eclipse, etc.).
As with Boost, some C++0x extensions encouragecoding practices that hamper readability—for example by removingchecked redundancy (such as type names) that may be helpful to readers,or by encouraging template metaprogramming. Other extensionsduplicate functionality available through existingmechanisms, which may lead toconfusion and conversion costs.
Decision: Use only C++0x libraries and language features that have been approvedfor use. Currently, no such features are approved.Features will be approved individually as appropriate.
Naming
The most important consistency rules are those that governnaming. The style of a name immediately informs us what sort ofthing the named entity is: a type, a variable, a function, aconstant, a macro, etc., without requiring us to search for thedeclaration of that entity. The pattern-matching engine in ourbrains relies a great deal on these naming rules.
Naming rules are pretty arbitrary, butwe feel that consistency is more important than individual preferencesin this area, so regardless of whether you find them sensible or not,the rules are the rules.
General Naming Rules
link▽Function names, variable names, and filenames should bedescriptive; eschew abbreviation. Types and variables should benouns, while functions should be "command" verbs.How to Name
Give as descriptive a name as possible, within reason. Donot worry about saving horizontal space as it is far moreimportant to make your code immediately understandable by anew reader. Examples of well-chosen names:
int num_errors; // Good.int num_completed_connections; // Good.
Poorly-chosen names use ambiguous abbreviations or arbitrarycharacters that do not convey meaning:
int n; // Bad - meaningless.int nerr; // Bad - ambiguous abbreviation.int n_comp_conns; // Bad - ambiguous abbreviation.
Type and variable names should typically be nouns: e.g.,FileOpener
,num_errors
.
Function names should typically be imperative (that is theyshould be commands): e.g., OpenFile()
,set_num_errors()
. There is an exception foraccessors, which, described more completely in Function Names, should be namedthe same as the variable they access.
Abbreviations
Do not use abbreviations unless they are extremely wellknown outside your project. For example:
// Good// These show proper names with no abbreviations.int num_dns_connections; // Most people know what "DNS" stands for.int price_count_reader; // OK, price count. Makes sense.
// Bad!// Abbreviations can be confusing or ambiguous outside a small group.int wgc_connections; // Only your group knows what this stands for.int pc_reader; // Lots of things can be abbreviated "pc".
Never abbreviate by leaving out letters:
int error_count; // Good.
int error_cnt; // Bad.
File Names
link▽Filenames should be all lowercase and can include underscores(_
) or dashes (-
). Follow theconvention that yourprojectuses. 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 filesshould end in .h
.
Do not use filenames that already existin /usr/include
, such as db.h
.
In general, make your filenames very specific. For example,use http_server_logs.h
ratherthan logs.h
. A very common case is to have apair of files called, e.g., foo_bar.h
and foo_bar.cc
, defining a classcalled FooBar
.
Inline functions must be in a .h
file. If yourinline functions are very short, they should go directly into your.h
file. However, if your inline functionsinclude a lot of code, they may go into a third file thatends in -inl.h
. In a class with a lot of inlinecode, your class could have three files:
url_table.h // The class declaration.url_table.cc // The class definition.url_table-inl.h // Inline functions that include lots of code.
See also the section -inl.h Files
Type Names
link▽Type names start with a capital letter and have a capitalletter for each new word, with no underscores:MyExcitingClass
, MyExcitingEnum
.The names of all types — classes, structs, typedefs, and enums— have the same naming convention. Type names should startwith a capital letter and have a capital letter for each newword. No underscores. For example:
// classes and structsclass UrlTable { ...class UrlTableTester { ...struct UrlTableProperties { ...// typedefstypedef hash_mapPropertiesMap;// enumsenum UrlTableErrors { ...
Variable Names
link▽Variable names are all lowercase, with underscores betweenwords. Class member variables have trailing underscores. Forinstance:my_exciting_local_variable
,my_exciting_member_variable_
.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 (also called instance variables or membervariables) are lowercase with optional underscores likeregular variable names, but always end with a trailingunderscore.
string table_name_; // OK - underscore at end.string tablename_; // OK.
Struct Variables
Data members in structs should be named like regularvariables without the trailing underscores that data membersin classes have.
struct UrlTableProperties {string name;int num_entries;}
See Structs vs. Classes for adiscussion of when to use a struct versus a class.
Global Variables
There are no special requirements for global variables,which should be rare in any case, but if you use one,consider prefixing it with g_
or some othermarker to easily distinguish it from local variables.
Constant Names
link▽Use ak
followed by mixed case:kDaysInAWeek
.All compile-time constants, whether they are declared locally,globally, or as part of a class, follow a slightly differentnaming convention from other variables. Use a k
followed by words with uppercase first letters:
const int kDaysInAWeek = 7;
Function Names
link▽Regular functions have mixed case; accessors and mutators matchthe name of the variable:MyExcitingFunction()
,MyExcitingMethod()
,my_exciting_member_variable()
,set_my_exciting_member_variable()
.Regular Functions
Functions should start with a capital letter and have acapital letter for each new word. No underscores.
If your function crashes upon an error, you should append OrDie tothe function name. This only applies to functions which could beused by production code and to errors that are reasonablylikely to occur during normal operation.
AddTableEntry()DeleteUrl()OpenFileOrDie()
Accessors and Mutators
Accessors and mutators (get and set functions) should matchthe name of the variable they are getting and setting. Thisshows an excerpt of a class whose instance variable isnum_entries_
.
class MyClass {public:...int num_entries() const { return num_entries_; }void set_num_entries(int num_entries) { num_entries_ = num_entries; }private:int num_entries_;};
You may also use lowercase letters for other very shortinlined functions. For example if a function were so cheapyou would not cache the value if you were calling it in aloop, then lowercase naming would be acceptable.
Namespace Names
link▽Namespace names are all lower-case, and based on project names andpossibly their directory structure:google_awesome_project
.See Namespaces for a discussion ofnamespaces and how to name them.
Enumerator Names
link▽Enumerators should be named either likeconstants or likemacros: eitherkEnumName
or ENUM_NAME
.Preferably, the individual enumerators should be named likeconstants. However, it is alsoacceptable to name them like macros. The enumeration name,UrlTableErrors
(andAlternateUrlTableErrors
), is a type, andtherefore 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 likemacros. This caused problems withname collisions between enum values and macros. Hence, thechange to prefer constant-style naming was put in place. Newcode should prefer constant-style naming if possible.However, there is no reason to change old code to useconstant-style names, unless the old names are actuallycausing a compile-time problem.
Macro Names
link▽You're not really going to definea macro, are you? If you do, they're like this:MY_MACRO_THAT_SCARES_SMALL_CHILDREN
.Please see the description ofmacros; in general macros should not be used.However, if they are absolutely needed, then they should benamed with all capitals and underscores.
#define ROUND(x) ...#define PI_ROUNDED 3.0
Exceptions to Naming Rules
link▽If you are naming something that is analogous to an existing Cor C++ entity then you can follow the existing naming conventionscheme.-
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 ourcode readable. The following rules describe what you shouldcomment and where. But remember: while comments are veryimportant, the best code is self-documenting. Giving sensiblenames to types and variables is much better than using obscurenames that you must then explain through comments.
When writing your comments, write for your audience: the nextcontributorwho will need to understand your code. Be generous — the nextone may be you!
Comment Style
link▽Use either the//
or /* */
syntax, as longas 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
link▽Start each file with a copyright notice, followed by adescription of the contents of the file.Legal Notice and Author Line
Every file should contain the following items, in order:
- a copyright statement (for example,
Copyright 2008 Google Inc.
) - a license boilerplate. Choose the appropriate boilerplate for the license used by the project (for example, Apache 2.0, BSD, LGPL, GPL)
- an author line to identify the original author of the file
If you make significant changes to a file that someone elseoriginally wrote, add yourself to the author line. This canbe very helpful when anothercontributorhas questions about the file and needs to know whom to contactabout it.
File Contents
Every file should have a comment at the top, below the copyrightnotice and author line, that describes the contents of the file.
Generally a .h
file will describe the classesthat are declared in the file with an overview of what theyare for and how they are used. A .cc
fileshould contain more information about implementation detailsor discussions of tricky algorithms. If you feel theimplementation details or a discussion of the algorithmswould be useful for someone reading the .h
,feel free to put it there instead, but mention in the.cc
that the documentation is in the.h
file.
Do not duplicate comments in both the .h
andthe .cc
. Duplicated comments diverge.
Class Comments
link▽Every class definition should have an accompanying comment thatdescribes what it is for and how it should be used.// Iterates over the contents of a GargantuanTable. Sample usage:// GargantuanTableIterator* iter = table->NewIterator();// for (iter->Seek("foo"); !iter->done(); iter->Next()) {// process(iter->key(), iter->value());// }// delete iter;class GargantuanTableIterator {...};
If you have already described a class in detail in thecomments at the top of your file feel free to simply state"See comment at top of file for a complete description", butbe sure to have some sort of comment.
Document the synchronization assumptions the class makes, ifany. If an instance of the class can be accessed by multiplethreads, take extra care to document the rules and invariantssurrounding multithreaded use.
Function Comments
link▽Declaration comments describe use of the function; comments atthe definition of a function describe operation.Function Declarations
Every function declaration should have comments immediatelypreceding it that describe what the function does and how touse it. These comments should be descriptive ("Opens thefile") rather than imperative ("Open the file"); the commentdescribes the function, it does not tell the function whatto do. In general, these comments do not describe how thefunction performs its task. Instead, that should be left tocomments in the function definition.
Types of things to mention in comments at the functiondeclaration:
- 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
NULL
. - 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 thecompletely obvious. Notice below that it is not necessaryto say "returns false otherwise" because this is implied.
// Returns true if the table cannot hold any more entries.bool IsTableFull();
When commenting constructors and destructors, remember thatthe person reading your code knows what constructors anddestructors are for, so comments that just say something like"destroys this object" are not useful. Document whatconstructors do with their arguments (for example, if theytake ownership of pointers), and what cleanup the destructordoes. If this is trivial, just skip the comment. It isquite common for destructors not to have a header comment.
Function Definitions
Each function definition should have a comment describingwhat the function does if there's anything tricky about how it doesits job. For example, in the definition comment you mightdescribe any coding tricks you use, give an overview of thesteps you go through, or explain why you chose to implementthe function in the way you did rather than using a viablealternative. For instance, you might mention why it mustacquire a lock for the first half of the function but why itis not needed for the second half.
Note you should not just repeat the comments givenwith the function declaration, in the .h
file orwherever. It's okay to recapitulate briefly what the functiondoes, but the focus of the comments should be on how it does it.
Variable Comments
link▽In general the actual name of the variable should be descriptiveenough to give a good idea of what the variable is used for. Incertain cases, more comments are required.Class Data Members
Each class data member (also called an instance variable ormember variable) should have a comment describing what it isused for. If the variable can take sentinel values withspecial meanings, such as NULL
or -1, document this.For example:
private:// Keeps track of the total number of entries in the table.// Used to ensure we do not go over the limit. -1 means// that we don't yet know how many entries the table has.int num_total_entries_;
Global Variables
As with data members, all global variables should have acomment describing what they are and what they are used for.For example:
// The total number of tests cases that we run through in this regression test.const int kNumTestCases = 6;
Implementation Comments
link▽In your implementation you should have comments in tricky,non-obvious, interesting, or important parts of your code.Class Data Members
Tricky or complicated code blocks should have commentsbefore 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 theend of the line. These end-of-line comments should beseparated from the code by 2 spaces. Example:
// If we have enough memory, mmap the data portion too.mmap_budget = max(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 thecode is doing, and comments that mention that an error hasalready been logged when the function returns.
If you have several comments on subsequent lines, it canoften be more readable to line them up:
DoSomething(); // Comment here so the comments line up.DoSomethingElseThatIsLonger(); // Comment here so there are 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.}
NULL, true/false, 1, 2, 3...
When you pass in NULL
, boolean, or literal integervalues to functions, you should consider adding a comment aboutwhat they are, or make your code self-documenting by usingconstants. For example, compare:
bool success = CalculateSomething(interesting_value,10,false,NULL); // What are these arguments??
versus:
bool success = CalculateSomething(interesting_value,10, // Default base value.false, // Not the first time we're calling this.NULL); // No callback.
Or alternatively, constants or self-describing variables:
const int kDefaultBaseValue = 10;const bool kFirstTimeCalling = false;Callback *null_callback = NULL;bool success = CalculateSomething(interesting_value,kDefaultBaseValue,kFirstTimeCalling,null_callback);
Don'ts
Note that you should never describe the codeitself. Assume that the person reading the code knows C++better than you do, even though he or she does not know whatyou are trying to do:
// Now go through the b array and make sure that if i occurs,// the next element is i+1.... // Geez. What a useless comment.
Punctuation, Spelling and Grammar
link▽Pay attention to punctuation, spelling, and grammar; it iseasier to read well-written comments than badly written ones.Comments should usually be written as completesentences with proper capitalization and periods at the end.Shorter comments, such as comments at the end of a line ofcode, can sometimes be less formal, but you should beconsistent with your style. Complete sentences are morereadable, and they provide some assurance that the comment iscomplete and not an unfinished thought.
Although it can be frustrating to have a code reviewer pointout that you are using a comma when you should be using asemicolon, it is very important that source code maintain ahigh level of clarity and readability. Proper punctuation,spelling, and grammar help with that goal.
TODO Comments
link▽UseTODO
comments for code that is temporary, ashort-term solution, or good-enough but not perfect.TODO
s should include the string TODO
inall caps, followed by thename, e-mail address, or otheridentifierof the person who can best provide context about the problemreferenced by the TODO
. A colon is optional. The mainpurpose is to have a consistent TODO
format that can besearched to find the person who can provide more details upon request.A TODO
is not a commitment that the person referencedwill fix the problem. Thus when you create a TODO
, it isalmost always yournamethat is given.
// TODO(kl@gmail.com): Use a "*" here for concatenation operator.// TODO(Zeke) change this to use relations.
If your TODO
is of the form "At a future date dosomething" make sure that you either include a very specificdate ("Fix by November 2005") or a very specific event("Remove this code when all clients can handle XML responses.").
Deprecation Comments
link▽Mark deprecated interface points withDEPRECATED
comments.You can mark an interface as deprecated by writing a comment containingthe word DEPRECATED
in all caps. The comment goes eitherbefore the declaration of the interface or on the same line as thedeclaration.
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 tofix their callsites. In C++, you can implement a deprecated function asan inline function that calls the new interface point.
Marking an interface point DEPRECATED
will not magicallycause any callsites to change. If you want people to actually stop usingthe deprecated facility, you will have to fix the callsites yourself orrecruit a crew to help you.
New code should not contain calls to deprecated interface points. Usethe new interface point instead. If you cannot understand thedirections, find the person who created the deprecation and ask them forhelp using the new interface point.
Formatting
Coding style and formatting are pretty arbitrary, but aprojectis much easier to follow if everyone uses the same style. Individualsmay not agree with every aspect of the formatting rules, and some ofthe rules may take some getting used to, but it is important that allproject contributorsfollow the style rules so thattheycan all read and understand everyone's code easily.
To help you format code correctly, we've created a settingsfile for emacs.
Line Length
link▽Each line of text in your code should be at most 80 characterslong.We recognize that this rule is controversial, but so much existingcode already adheres to it, and we feel that consistency isimportant.
Pros: Those who favorthis rule arguethat it is rude to force them to resize their windows and thereis no need for anything longer. Some folks are used to havingseveral code windows side-by-side, and thus don't have room towiden their windows in any case. People set up their workenvironment assuming a particular maximum window width, and 80columns has been the traditional standard. Why change it?
Cons: Proponents of change argue that a wider line can make codemore readable. The 80-column limit is an hideboundthrowback to 1960s mainframes;modern equipment haswide screens that can easily show longer lines.
Decision:
80 characters is the maximum.
Exception: if a comment line contains an example command ora literal URL longer than 80 characters, that line may belonger than 80 characters for ease of cut and paste.
Exception: an #include
statement with a longpath may exceed 80 columns. Try to avoid situations where thisbecomes necessary.
Exception: you needn't be concerned aboutheader guardsthat exceed the maximum length.
Non-ASCII Characters
link▽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 certaincases it is appropriate to include such words in your code. Forexample, if your code parses data files from foreign sources,it may be appropriate to hard-code the non-ASCII string(s) used inthose data files as delimiters. More commonly, unittest code(which does notneed to be localized) might contain non-ASCII strings. In suchcases, you should use UTF-8, since that isan encoding understood by most tools ableto handle more than just ASCII.Hex encoding is also OK, and encouraged where it enhancesreadability — for example, "\xEF\xBB\xBF"
is theUnicode zero-width no-break space character, which would beinvisible if included in the source as straight UTF-8.
Spaces vs. Tabs
link▽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 tabkey.
Function Declarations and Definitions
link▽Return type on the same line as function name, parameters on thesame line if they fit.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 indentType par_name2,Type par_name3) {DoSomething(); // 2 space indent...}
Some points to note:
- The return type is always on the same line as the function name.
- 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 at the end of the same line as the last parameter.
- The close curly brace is either on the last line by itself or (if other style rules permit) 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 named, with identical names in the declaration and implementation.
- All parameters should be aligned if possible.
- Default indentation is 2 spaces.
- Wrapped parameters have a 4 space indent.
If your function is const
, the const
keyword should be on the same line as the last parameter:
// Everything in this function signature fits on a single lineReturnType FunctionName(Type par) const {...}// This function signature requires multiple lines, but// the const keyword is on the line with the last parameter.ReturnType ReallyLongFunctionName(Type par1,Type par2) const {...}
If some parameters are unused, comment out the variable name in thefunction definition:
// Always have named parameters in interfaces.class Shape {public:virtual void Rotate(double radians) = 0;}// Always have named parameters in the declaration.class Circle : public Shape {public:virtual void Rotate(double radians);}// Comment out unused named parameters in definitions.void Circle::Rotate(double /*radians*/) {}
// Bad - if someone wants to implement later, it's not clear what the// variable means.void Circle::Rotate(double) {}
Function Calls
link▽On one line if it fits; otherwise, wrap arguments at theparenthesis.Function calls have the following format:
bool retval = DoSomething(argument1, argument2, argument3);
If the arguments do not all fit on one line, they should bebroken up onto multiple lines, with each subsequent linealigned with the first argument. Do not add spaces after theopen paren or before the close paren:
bool retval = DoSomething(averyveryveryverylongargument1,argument2, argument3);
If the function has many arguments, consider having one perline if this makes the code more readable:
bool retval = DoSomething(argument1,argument2,argument3,argument4);
If the function signature is so long that it cannot fit withinthe maximum line length, you mayplace all arguments on subsequent lines:
if (...) {......if (...) {DoSomethingThatRequiresALongFunctionName(very_long_argument1, // 4 space indentargument2,argument3,argument4);}
Conditionals
link▽Prefer no spaces inside parentheses. Theelse
keyword belongs on a new line.There are two acceptable formats for a basic conditionalstatement. One includes spaces between the parentheses and thecondition, and one does not.
The most common form is without spaces. Either is fine, butbe consistent. If you are modifying a file, use theformat that is already present. If you are writing new code,use the format that the other files in that directory orproject 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 { // The else goes on the same line as the closing brace....}
If you prefer you may add spaces inside theparentheses:
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 theif
and the open parenthesis. You must also havea space between the close parenthesis and the curly brace, ifyou'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 ifthis enhances readability. You may use this only when theline is brief and the statement does not use theelse
clause.
if (x == kFoo) return new Foo();if (x == kBar) return new Bar();
This is not allowed when the if statement has anelse
:
// Not allowed - IF statement on one line when there is an ELSE clauseif (x) DoThis();else DoThat();
In general, curly braces are not required for single-linestatements, but they are allowed if you like them;conditional or loop statements with complex conditions orstatements may be more readable with curly braces. Someprojectsrequire that an if
must always always have anaccompanying 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 ELSEif (condition) {foo;} elsebar;// Not allowed - curly on ELSE but not IFif (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
link▽Switch statements may use braces for blocks. Empty loop bodies should use{}
or continue
.case
blocks in switch
statements can havecurly braces or not, depending on your preference. If you doinclude curly braces they should be placed as shown below.
If not conditional on an enumerated value, switch statementsshould always have a default
case (in the case ofan enumerated value, the compiler will warn you if any valuesare not handled). If the default case should never execute,simplyassert
:
switch (var) {case 0: { // 2 space indent... // 4 space indentbreak;}case 1: {...break;}default: {assert(false);}}
Empty loop bodies should use {}
orcontinue
, but not a single semicolon.
while (condition) {// Repeat test until it returns false.}for (int i = 0; i < kSomeNumber; ++i) {} // Good - empty body.while (condition) continue; // Good - continue indicates no logic.
while (condition); // Bad - looks like part of do/while loop.
Pointer and Reference Expressions
link▽No spaces around period or arrow. Pointer operators do not havetrailing spaces.The following are examples of correctly-formatted pointer andreference 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 placethe asterisk adjacent to either the type or to the variablename:
// These are fine, space preceding.char *c;const string &str;// These are fine, space following.char* c; // but remember to do "char* c, *d, *e, ...;"!const string& str;
char * c; // Bad - spaces on both sides of *const string & str; // Bad - spaces on both sides of &
You should do this consistently within a singlefile,so, when modifying an existing file, use the style in thatfile.
Boolean Expressions
link▽When you have a boolean expression that is longer than the standard line length, be consistent inhow you break up the lines.In this example, the logical AND operator is always at the endof the lines:
if (this_one_thing > this_other_thing &&a_third_thing == a_fourth_thing &&yet_another && last_one) {...}
Note that when the code wraps in this example, both ofthe &&
logical AND operators are at theend of the line. This is more common in Google code, thoughwrapping all operators at the beginning of the line is alsoallowed. Feel free to insert extra parentheses judiciously,because they can be very helpful in increasing readabilitywhen used appropriately. Also note that you should always use thepunctuation operators, such as &&
and~
, rather than the word operators, such as and
and compl
.
Return Values
link▽Do not needlessly surround thereturn
expression withparentheses.Use parentheses in return expr;
only where you would usethem in x = expr;
.
return result; // No parentheses in the simple case.return (some_long_condition && // Parentheses ok to make a complexanother_condition); // expression more readable.
return (value); // You wouldn't write var = (value);return(result); // return is not a function!
Variable and Array Initialization
link▽Your choice of=
or ()
.You may choose between =
and ()
; thefollowing are all correct:
int x = 3;int x(3);string name("Some Name");string name = "Some Name";
Preprocessor Directives
link▽The hash mark that starts a preprocessor directive shouldalways be at the beginning of the line.Even when preprocessor directives are within the body ofindented code, the directives should start at the beginning ofthe line.
// Good - directives at beginning of lineif (lopsided_score) {#if DISASTER_PENDING // Correct -- Starts at beginning of lineDropEverything();# if NOTIFY // OK but not required -- Spaces after #NotifyClient();# endif#endifBackToNormal();}
// Bad - indented directivesif (lopsided_score) {#if DISASTER_PENDING // Wrong! The "#if" should be at beginning of lineDropEverything();#endif // Wrong! Do not indent "#endif"BackToNormal();}
Class Format
link▽Sections inpublic
, protected
andprivate
order, each indented one space.The basic format for a class declaration (lacking thecomments, see Class Comments fora 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_;DISALLOW_COPY_AND_ASSIGN(MyClass);};
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 theprivate
section. - See Declaration Order for rules on ordering declarations within each of these sections.
Constructor Initializer Lists
link▽Constructor initializer lists can be all on one line or withsubsequent lines indented four spaces.There are two acceptable formats for initializer lists:
// When it all fits on one line:MyClass::MyClass(int var) : some_var_(var), some_other_var_(var + 1) {}
or
// When it requires multiple lines, indent 4 spaces, putting the colon on// the first initializer line:MyClass::MyClass(int var): some_var_(var), // 4 space indentsome_other_var_(var + 1) { // lined up...DoSomething();...}
Namespace Formatting
link▽The contents of namespaces are not indented.Namespaces do not add an extra level ofindentation. 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
link▽Use of horizontal whitespace depends on location. Never put trailingwhitespace 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.int x[] = { 0 }; // Spaces inside braces for array initialization areint x[] = {0}; // optional. If you use them, put them on both sides!// 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 editingthe same file, when they merge, as can removing existing trailingwhitespace. So: Don't introduce trailing whitespace. Remove itif you're already changing that line, or do it in a separateclean-upoperation (preferably when no-one elseis 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) {switch ( i ) { // Loops and conditions may have spaces insideif ( test ) { // parentheses, but this is rare. Be consistent.for ( int i = 0; i < 5; ++i ) {for ( ; i < 5 ; ++i) { // For loops always have a space after the... // semicolon, and may have a space before the// semicolon.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
x = 0; // Assignment operators always have spaces around// them.x = -5; // No spaces separating unary operators and their++x; // arguments.if (x && !y)...v = w * x + y / z; // Binary operators usually have spaces around them,v = w*x + y/z; // but it's okay to remove spaces around factors.v = w * (x + z); // Parentheses should have no spaces inside them.
Templates and Casts
vectorx; // No spaces inside the angley = static_cast (x); // brackets (< and >), before// <, or between >( in a cast.vector x; // Spaces between type and pointer are// okay, but be consistent.set > x; // C++ requires a space in > >.set< list
> x; // You may optionally use// symmetric spacing in < <.
Vertical Whitespace
link▽Minimize use of vertical whitespace.This is more a principle than a rule: don't use blank lineswhen you don't have to. In particular, don't put more thanone or two blank lines between functions, resist startingfunctions with a blank line, don't end functions with a blankline, and be discriminating with your use of blank linesinside functions.
The basic principle is: The more code that fits on one screen,the easier it is to follow and understand the control flow ofthe program. Of course, readability can suffer from codebeing too dense as well as too spread out, so use yourjudgement. But in general, minimize use of verticalwhitespace.
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 wediscuss here.
Existing Non-conformant Code
link▽You may diverge from the rules when dealing with code that does notconform to this style guide.If you find yourself modifying code that was written tospecifications other than those presented by this guide, you mayhave to diverge from these rules in order to stay consistent withthe local conventions in that code. If you are in doubt abouthow to do this, ask the original author or the person currentlyresponsible for the code. Remember that consistencyincludes local consistency, too.
Windows Code
link▽Windows programmers have developed their own set of codingconventions, mainly derived from the conventions in Windows headersand other Microsoft code. We want to make it easy for anyone tounderstand your code, so we have a single set of guidelines foreveryone writing C++ on any platform.It is worth reiterating a few of the guidelines that you mightforget 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, useconst TCHAR *
instead ofLPCTSTR
. - 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 asDLLIMPORT
andDLLEXPORT
, so that someone can easily disable the extensions if they share the code.
However, there are just a few rules that we occasionally needto 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 thecode around you and determine its style. If they use spacesaround their if
clauses, you should, too. Iftheir comments have little boxes of stars around them, makeyour comments have little boxes of stars around them too.
The point of having style guidelines is to have a commonvocabulary of coding so people can concentrate on what you aresaying, rather than on how you are saying it. We presentglobal style rules here so people know the vocabulary. Butlocal style is also important. If code you add to a filelooks drastically different from the existing code around it,the discontinuity throws readers out of their rhythm when theygo to read it. Try to avoid this.
OK, enough writing about writing code; the code itself is muchmore interesting. Have fun!
Revision 3.188
Benjy WeinbergerCraig Silverstein
Gregory Eitzmann
Mark Mentovai
Tashana Landray