KEMBAR78
Google CPP Style Guide | PDF
0% found this document useful (0 votes)
97 views75 pages

Google CPP Style Guide

google cpp programming guide
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF or read online on Scribd
0% found this document useful (0 votes)
97 views75 pages

Google CPP Style Guide

google cpp programming guide
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF or read online on Scribd
You are on page 1/ 75
enzo Google C++ Syle Guide Google C++ Style Guide Table of Contents He Fi leader i Classes le- der les, lass: Gov Specific Comments hrpevigoogl.g be alsoguideeppguide id Self-contained Headers The tidefine Guard Forward Declarations Inline Functions Names and Order of Includes Namespaces Unnamed Namespaces and Static Variables Nonmember, Static Member, and Global Functions Local Variables Static and Global Variables Doing Work in Constructors Implicit Conversions Copyable and Movable Types Structs vs. Classes Inheritance Multiple Inheritance Interfaces Operator Overloading Access Control Declaration Order General Naming Rules File Names Type Names Variable Names Constant Names Function Names Namespace Names Enumerator Names Macro Names Exceptions fo Naming Rules Comment Style File Comments Class Comments Function Comments Variable Comments Implementation Comments Punctuation, Spelling and TODO Comments Depracation Comments ezeotr Google C++ Syle Guide Exceptions: Existing Non-conformant Code Windows Cade tothe Rules Background C++ is one of the main development languages used by many of Google's open-source projects. As every C++ programmer knows, the language has many powerful features, but this power brings with it complexity, which in tum can make cade more bug-prone and harder to read and maintain. ‘The goal of this guide is to manage this complexity by describing in detail the dos and don'ts of writing C++ code. These rules exist to keep the code base manageable while stil allowing coders to use C++ language features productively. Style, also known as readability, is what we call the conventions that govem our C++ code. ‘The term Style is a bit of a misnomer, since these conventions cover far more than just source file formatting. Most open-source projects developed by Google conform to the requirements in this guide. Note that this guide is not a C++ tutorial: we assume that the reader is familiar with the language. ©°Goals of the Style G Why do we have this document? ‘There are a few core goals that we believe this guide should serve. These are the fundamental ‘whys that underlie all of the individual rules. By bringing these ideas to the fore, we hope to ground discussions and make it clearer to our broader community why the rules are in place and why particular decisions have been made. If you understand what goals each rule is serving, it should be clearer to everyone when a rule may be waived (some can be), and what, sort of argument or alternative would be necessary to change a rule in the guide. The goals of the style guide as we currently see them are as follows: Style rules should pull their weight ‘The benefit ofa style rule must be large enough to justify asking all of our engineers to remember it, The benefit is measured relative to the codebase we would get without the rule, so a rule against a very harmful practice may still have a small benefit if People are unlikely to do it anyway. This principle mostly explains the rules we don't have, rather than the rules we do: for example, goto contravenes many of the following Principles, but is already vanishingly rare, so the Style Guide doesn't discuss it. hpsigooge.g iu fs uidecppgui de hit 28 ezeotr ‘Google C++ Sle Guide Optimize for the reader, not the writer ‘Our codebase (and most individual components submitted to it) is expected to Continue for quite some time. As a result, more time willbe spent reading most of our ‘code than writing it. We explicitly choose to optimize for the experience of our average software engineer reading, maintaining, and debugging code in our codebase rather than ease when writing said code. "Leave a trace for the reader" is a particulary ‘common sub-point ofthis principle: When something surprising or unusual is happening in a snippet of code (for example, transfer of pointer ownership), leaving textual hints forthe reader at the point of use is valuable (std: :unique_ptr demonstrates the ownership transfer unambiguously atthe call site) Be consistent with existing code Using one style consistently through our codebase lets us focus on other (more important) issues. Consistency also allows for automation: tools that format your code fr adjust your #includes only work properly when your code is consistent with the ‘expectations of the tooling. In many cases, rules that are attributed to "Be Consistent" boll down to "Just pick one and stop worrying about it; the potential value of allowing {lexibilty on these points is outweighed by the cost of having people argue over them. Be consistent with the broader C++ community when appropriate Consistency with the way other organizations use C++ has value for the same reasons as consistency within our code base. Ifa feature in the C++ standard soles a problem, or if some idiom is widely known and accepted, that's an argument for using it. Howeter, sometimes standard features and idioms are flawed, or were just designed without our codebase's needs in mind. In those cases (as described below) i's ‘appropriate to constrain or ban standard features. In some cases we prefer a homegrown or third-party library over a library defined in the C++ Standard, ether out ‘of perceived superiority or insufficient value to transition the codebase to the standard interface. ‘Avoid surprising or dangerous constructs ‘C++ has features that are more surprising or dangerous than one might think at a glance. Some style guide restrictions are in place to prevent falling into these pitas. ‘There is a high bar for style guide waivers on such restrictions, because wahing such rules often directly risks compromising program corectness. ‘Avoid constructs that our average C++ programmer would find tricky or hard to maintain ‘C4 has features that may not be generally appropriate because of the complexity they introduce to the code. in widely used code, it may be more acceptable to use trickier language constructs, because any benefits of more complex implementation are multiplied widely by usage, and the cost in understanding the complexity does not need to be paid again when working with new portions ofthe codebase, When in ddoubl, waivers to rules of this type can be sought by asking your project leads. This is ‘specifically important for our codebase because code ownership and team membership changes over time: even if everyone that works with some piece of code currently understands it, such understanding is not guaranteed to hold a few years from now. Be mindful of our scale With a codebase of 100+ milion lines and thousands of engineers, some mistakes ‘and simplifications for one engineer can become costly for many. For instance it's particularly important to avoid polluting the global namespace: name colisions across a codebase of hundreds of millions of fines are dificult to work with and hard to avoid it ‘everyone puts things into the global namespace. Concede to optimization when necessary Performance optimizations can sometimes be necessary and appropriate, even when they conflict with the other principles ofthis document. ‘The intent of this document is to provide maximal guidance with reasonable restriction, As always, common sense and good taste should prevail. By this we specifically refer to the established conventions of the entire Google C++ community, not just your personal Preferences or those of your team. Be skeptical about and reluctant to use clever or unusual constructs: the absence of a prohibition is not the same as a license to proceed. Use your judgment, and if you are unsure, please don't hesitate to ask your project leads to get additional input. hpsuigoogle.g iu fs uidecrpgul de hit 378 ezeotr Google C++ Syle Guide °°Header Files In general, every .cc fle should have an associated .h file. There are some common exceptions, such as unittests and small .c¢ fles containing just a main() function Correct use of header fles can make a huge difference to the readability, size and performance of your code. ‘The following rules will guide you through the various pitfalls of using header file. ©Self-contained Headers Header files should be self-contained (compile on their own) and end in .h. Nor-header files that are meant for inclusion should end in . inc and be used sparingly. All header files should be self-contained. Users and refactoring tools should not have to ‘adhere to special conditions to include the header. Specifically, a header should have header ‘guards and include all other headers it needs. Prefer placing the definitions for template and inline functions in the same fle as thelr declarations. The definitions of these constructs must be included into every .cc file that ses them, or the program may fail to link in some build configurations, If declarations and definitions are in different files, including the former should transitively include the latter. Do not move these definitions to separately included header files (~in1.h); this practice was common in the past, but is no longer allowed As an exception, a template that is explicitly instantiated for all relevant sets of template arguments, or that is a private implementation detail of a class, is allowed to be defined in the cone and only .cc file that instantiates the template, ‘There are rare cases where a file designed to be included is not self-contained. These are typically intended to be included at unusual locations, such as the middle of another fle. They might not use header quards, and might not include their prerequisites. Name such files with the inc extension, Use sparingly, and prefer self-contained headers when possible. ©The #define Guard Al header files should have #tdefine guards to prevent multiple inclusion. The format of the symbol name should be ___H_ To guarantee uniqueness, they should be based on the full path in a project's source tree. For example, the file Foo/src/bar/baz.h in project foo should have the following guard: ifndef FOO_BAR_BAZ_H_ define FOO_BAR_BAZH_ endif // FOO_BAR_BAZ H_ hpsuigoogle.g iu fs uidecrpgul de hit 478 ezeotr Google C++ Syle Guide °° Forward Declarations ‘Avoid using forward declarations where possible. Just #include the headers you need, Definition: A “forward declaratio definition is a declaration of a class, function, or template without an associated Pros: + Forward declarations can save compile time, as includes force the compiler to open more files and process more input. + Forward declarations can save on unnecessary recompilation. ##includes can force your code to be recompiled more often, due to unrelated changes in the header. + Forward declarations can hide a dependency, allowing user code to skip necessary recompilation when headers change + A forward declaration may be broken by subsequent changes to the library. Forward declarations of functions and templates can prevent the header owners from making ‘otherwise-compatible changes to their APIs, such as widening a parameter type, adding a template parameter with a default value, or migrating to a new namespace. + Forward declaring symbols from namespace std: : yields undefined behavior. + It can be dificult to determine whether a forward declaration or a full include is needed, Replacing an #include with a forward declaration can silently change the meaning of code: If b. struct B {); struct D: BQ); I) good_user.ce: include "b. void £(8*); void F(void*); void test(D* x) { f(x)5 } // calls F(B*) Ifthe sinclude was replaced with forward decls for 8 and D, test() would call f(void*), + Forward dectaring multiple symbols from a header can be more verbose than simply #includeing the header. + Structuring code to enable forward declarations (e.g. using pointer members instead of object members) can make the code slower and more complex. Decision: + Try to avwid forward declarations of entities defined in another project. + When using a function declared in a header fle, always #include that header. + When using a class template, prefer to #include its header fle. Please see Names and Order of Includes for rules about when to #include a header, Inline Functions hpsuigoogle.g iu fs uidecrpgul de hit 78 ezeotr Google C++ Syle Guide Define functions inline only when they are small, say, 10 lines or fewer. Definition: You can dectare functions in a way that allows the compiler to expand them inline rather than calling them through the usual function call mechanism. Pros: Inlining @ function can generate more efficient object code, as long as the inlined function is small. Feel free to inline accessors and mutators, and other short, performance-critical functions, Cons: Overuse of inlining can actually make programs slower. Depending on a function's size, inlining it can cause the code size to increase or decrease. inlining a very small accessor function will usually decrease code size while inlining a very large function can dramatically increase code size. On modem processors smaller code usually runs faster due to better use of the instruction cache, Decision: ‘A decent rule of thumb is to not inline a funetion ifit is more than 10 lines long. Beware of destructors, which are often longer than they appear because of implicit member. and base- destructor calls! Another useful rule of thumb: i's typically not cost effective to inline functions with loops or switch statements (unless, in the common case, the loop or switch statement is never executed), It is important to know that functions are not always inlined even if they are declared as such; for example, virtual and recursive functions are not normally inlined, Usually recursive functions should not be inline, The main reason for making a virtual function inline is to place its definition in the class, either for convenience or to document its behavior, €.g., for accessors and mutators, °°Names and Order of Includes Use standard order for readability and to avoid hidden dependencies: Related header, C library, C++ library, other libraries’ .h, your project's .h. All of a project's header files should be listed as descendants of the project's source directory ‘without use of UNKX directory shortcuts . (the current directory) or ... (the parent directory), For example, google-awesome-project/src/base/logging-h should be included as: #include “base/logging-h” In dir/foo.ce or dir/foo_test.cc, whose main purpose is to implement or test the stuff in dir2/foo2.h, order your includes as follows: 1. dir2/foo2.h, 2. C system files. 3. Cr+ system files. 4. Other libraries’ hn files. 5. Your project's .h files. hpsuigoogle.g iu fs uidecrpgul de hit ans. ezeotr Google C++ Syle Guide With the preferred ordering, if dir2/foo2.h omits any necessary includes, the build of dir/foo.cc of dir/foo_test.cc will break. Thus, this rule ensures that build breaks show Up first for the people working on these files, not for innocent people in other packages. dir/foo.cc and dir2/foo2.h are usually in the same directory (e.g, base/basictypes_test.cc and base/basictypes.h), but may sometimes be in different directories too. Within each section the includes should be ordered alphabetically. Note that older code might not conform to this rule and should be fixed when convenient, You should include all the headers that define the symbols you rely upon, except in the Unusual case of forward declaration. if you rely on symbols from bar.h, don't count on the fact that you included foo..h which (currently) includes bar.h: include bar.h yourself, unless oo.h explicitly demonstrates its intent to provide you the symbols of bar, Howover, any includes present in the related header do not need to be included again in the related cc (i.e., foo.c¢ can rely on foo..'s includes), For example, the includes in google-awesone-project/src/foo/internal/fooserver.cc might look like this: include "foo/server/fooserver.h” include include #include #include #include "base/basictypes.h’ include “base/conmandlineflags. include “foo/server/bar-h" Exception: ‘Sometimes, systom-speciic code needs conditional includes. Such code can put conditional includes after other includes. Of course, keep your system-specific code small and localized. Example: include “foo/public/fooserver.h" include “base/port.h" // For LANG_OXA1. ifdef LANG_OOL #include #endif // LANG_COAT “Scoping °°Namespaces hpsuigoogle.g iu fs uidecrpgul de hit 08 ezeotr Google C++ Syle Guide With few exceptions, place code in a namespace. Namespaces should have unique names based on the project name, and possibly its path. Do not use using-directives (e.g. using namespace foo). Do not use inline namespaces. For unnamed namespaces, see Unnamed Namespaces and Static Variables. Definition: Namespaces subdivide the global scope into distinct, named scopes, and so are useful for preventing name collisions in the global scope. Pros: Namespaces provide a method for preventing name conflicts in large programs while allowing most code to use reasonably short names, For example, if two diferent projects have a class Foo in the global scope, these symbols may collide at compile time or at runtime. if each project places their code in a namespace, project: :Foo and project2: :Foo are now distinct symbols that do not collide, and code ‘within each project's namespace can continue to refer to Foo without the prefix. Inline namespaces automatically place their names in the enclosing scope. Consider the following snippet, for example: namespace X { inline namespace ¥ { void f00()3 3 // namespace Y 3 7/7 namespace X The expressions x: :Y::f00() and x: :00() are interchangeable. Inline namespaces are primarily intended for AB! compatibility across versions. Cons: Namespaces can be confusing, because they complicate the mechanics of figuring out what definition a name refers to. Inline namespaces, in particular, can be confusing because names aren't actually restricted to the namespace where they are declared. They are only useful as part of some larger versioning policy. In some contexts, i's necessary to repeatedly refer to symbols by their fully-qualified names. For deeply-nested namespaces, this can add a lot of clutter. Decision: Namespaces should be used as follows: + Follow the rules on Namespace Names. + Terminate namespaces with comments as shown in the given examples. + Namespaces wrap the entire source fle after includes, gflags defiitions/declarations and forward declarations of classes from other namespaces. J/ In the -h file anespace mynanespace { // All declarations are within the namespace scope. // Notice the lack of indentation. class MyClass { public: void Foo(); psuigoogl.g uals uidecrpguide hit ws ezeotr Google C++ Syle Guide h } // namespace mynamespace // In the .cc file namespace mynanespace { // Definition of functions is within scope of the namespace. void MyClass::Fo0() { } } // namespace mynamespace More complex .cc files might have additional details, like flags or using-declarations. ‘include "a." DEFINE FLAG(booL, soneflag, false, “dummy flag"); namespace a { using ::fo0::bar; s+.code for a... // Code goes against the left margin. } // namespace a + Do not declare anything in namespace st, including forward declarations of standard library classes, Declaring entities in namespace std is undefined behavior, i,e., not portable, To declare entities from the standard library, include the appropriate header file, + You may not use a using-directive to make all names from a namespace available. // Forbidden -- This pollutes the namespace. Using namespace fo + Do not use Namespace aliases at namespace scope in header files except in ‘explicitly marked intemal-only namespaces, because anything imported into a namespace in a header file becomes part of the public AP! exported by that fle, // Shorten access to some commonly used names in .cc files. namespace baz = ::fo0::bar::bazj // Shorten access to sone commonly used nanes (ina -h file). aespace Librarian { namespace inpl { // Internal, not part of the API. namespace sidetable = ::pipeline diagnostics: :sidetable; } // namespace inpl inline void my_inline_function() { 71 namespace alias local to 2 function (or method). namespace baz ‘00: sbar::baz3 . } // namespace librarian *+ Do not use inline namespaces. hpsuigoogle.g iu fs uidecrpgul de hit os. ezeotr Google C++ Syle Guide ©°Unnamed Namespaces and Static Variables When definitions in a .cc fle do not need to be referenced outside that fle, place them in an unnamed namespace or declare them static. Do not use either of these constructs in .h files, Definition: All declarations can be given intemal linkage by placing them in unnamed namespaces, and functions and variables can be given intemal linkage by declaring them static. This means that anything you're declaring can't be accessed from another file, ifa different fle declares something with the same name, then the two entities are completely independent, Decision: Use of internal linkage in .c¢ files is encouraged for all code that does not need to be referenced elsewhere, Do not use intemal linkage in . files, Format unnamed namespaces like named namespaces. In the terminating comment, leave the namespace name empty: namespace { ¥// namespace ©°Nonmember, Static Member, and Global Functions Prefer placing nonmember functions in a namespace; use completely global functions rarely. Prefer grouping functions with a namespace instead of using a class as if it were a namespace. Static methods of a class should generally be closely related to instances of the class or the class's static data, Pros: Nonmember and static member functions can be useful in some situations. Putting nonmember functions in a namespace avoids polluting the global namespace. Cons: Nonmember and static member functions may make more sense as members of anew class, especially if they access extemal resources or have significant dependencies. Decision: ‘Sometimes it is useful to define a function not bound to a class instance. Such a function ‘can be either a static member or a nonmember function. Nonmember functions should not depend on external variables, and should nearly always exist ina namespace. Rather than creating classes only to group static member functions which do not share static data, use namespaces instead. For a header nyproject/Foo_bar.h, for example, write namespace myproject { namespace foo_bar { void Functioni(); void Function2(); psigoogl.g iu fs uidecppguid hit 1075. ezeotr Google C++ Syle Guide } // namespace foo_bar } 7 namespace myproject instead of namespace myproject { class Foobar { public: static void Functiont(); static void Function2(); b }' // namespace myproject you define a nonmember function and it is only needed in its .cc file, use intemal linkage to limit its scope. °Local Variables Place a function's variables in the narrowest scope possible, and initialize variables in the declaration. C++ allows you to declare variables anywhere in a function. We encourage you to declare them in as local a scope as possible, and as close to the first use as possible. This makes it easier for the reader to find the declaration and see what type the variable is and what it was initialized to. in particular, initialization should be used instead of declaration and assignment, eg. int i; i= £05 // Bad -- initialization separate from declaration. int j = g()3 // Good -- declaration has initialization. std::vectorcint> v3 v.push_back(1); // Prefer initializing using brace initialization. v.push_back(2) 5 st vector v = (1, 2}; // Good -- v starts initialized. Variables needed for if, while and for statements should normally be declared within those statements, so that such variables are confined to those scopes. E.g. while (const char* p = strehr(str, ‘/')) str = p +25 ‘There is one caveat: if the variable is an object, its constructor is invoked every time it enters scope and is created, and its destructor is invoked every time it goes out of scope. // Inefficient implenentation: for (int i = @; i < 1000000; ++i) { Foo f; // My ctor and dtor get called 1000000 times each. .DoSomething (i); y It may be more efficient to declare such a variable used in a loop outside that loop: hpsuigoogle.g iu fs uidecrpgul de hit 08 ezeotr Google C++ Sle Guide Foo #5 _// My ctor and dtor get called once each. for (int i = @; 4 < 1¢00000; ++i) { .DoSonething(i); y °Static and Global Variables Variables of class type with static storage duration are forbidden: they cause haro-find bugs due to indeterminate order of construction and destruction. However, such variables are allowed if they are constexpr: they have no dynamic initialization or destruction, Objects with static storage duration, including global variables, static variables, static class member variables, and function static variables, must be Plain Old Data (POD): only ints, chars, floats, or pointers, or arrays/structs of POD. The order in which class constructors and initializers for static variables are called is only partially specified in C++ and can even change from build to build, which can cause bugs that are difficult to find, Therefore in addition to banning globals of class type, we do not allow non- local static variables to be initialized with the result of a function, unless that funetion (such as getenu), or getpid()) does not itself depend on any other globals. However, a static POD variable within function scope may be initialized with the result of a function, since its Initialization order is well-defined and does not occur until control passes through its declaration. Likewise, global and static variables are destroyed when the program terminates, regardless cof whether the termination is by retuming from main() or by calling exit(). The order in which destructors are called is defined to be the reverse of the order in which the constructors were called. Since constructor order is indeterminate, so is destructor order. For example, at program-end time a static variable might have been destroyed, but code stil running — pethaps in another thread — tries to access it and fails. Or the destructor for a static string. \ariable might be run prior to the destructor for another variable that contains a reference to that string One way to alleviate the destructor problem is to terminate the program by calling quick_exit() instead of exit(). The difference is that quick_exit() does not invoke destructors and does not invoke any handlers that were registered by calling atexit(). if you have @ handler that needs to run when a program terminates va quick_exit() (lushing logs, for example), you can register it using at_quick_exit(). (Ifyou have @ handler that needs to run at both exit() and quick_exit(), you need to register it in both places.) ‘As a result we only allow static variables to contain POD data, This rule completely disallows std: :vector (use C arrays instead), or string (use const char []). you need a static or global variable of a class type, consider initializing a pointer (which will never be freed), from either your main) function or from pthread_once(). Note that this must be a raw pointer, not a "smart" pointer, since the smart pointer’s destructor will have the order-of destructor issue that we are trying to avoid, °°Classes Classes are the fundamental unit of code in C++. Naturally, we use them extensively. This section lists the main dos and don'ts you should follow when writing a class. hpsuigoogle.g iu fs uidecrpgul de hit 08 ezeotr Google C++ Syle Guide ©°Doing Work in Constructors ‘Avoid virtual method calls in constructors, and avoid initialization that can fail if you cant signal an error. Definition: Itis possible to perform arbitrary initialization in the body of the constructor. Pros: + No need to wory about whether the class has been initialized or not. + Objects that are fully initialized by constructor call can be const and may also be easier to use with standard containers or algorithms. * Ifthe work calls virtual functions, these calls will not get dispatched to the subclass implementations. Future modification to your class can quietly introduce this problem ‘even if your class is not currently subclassed, causing much contusion, + There is no easy way for constructors to signal errors, short of crashing the program (not always appropriate) or using exceptions (which are forbidden), + Ifthe work fails, we now have an object whose initialization code failed, so it may be ‘an unusual state requiring a bool TsValid() state checking mechanism (or similar) which is easy to forget to call + You cannot take the address of a constructor, so whatever work is done in the constructor cannot easily be handed off to, for example, another thread. Decision: Constructors should never call virtual functions. lf appropriate for your code , terminating the rogram may be an appropriate error handling response. Otherwise, consider a factory function or Init() method. Avoid Init() methods on objects with no other states that affect ‘which public methods may be called (semi-constructed objects of this form are particularly hard to work with correctly), Implicit Conversions Do not define implicit conversions. Use the explicit keyword for conversion operators and single-argument constructors. Definition: Implicit conversions allow an object of one type (called the source type) to be used where a diferent type (called the destination type) is expected, such as when passing an int argument to a function that takes a double parameter. In adcition to the implicit conversions defined by the language, users can define their own, by adding appropriate members to the class definition of the source or destination type. An implicit conversion in the source type is defined by a type conversion operator named after the destination type (¢.g. operator bool ()). An implicit conversion in the destination type is defined by a constructor that can take the Source type as its only argument (or only argument with no default value) hpsuigoogle.g iu fs uidecrpgul de hit 1995, ezeotr Google C++ Syle Guide ‘The explicit keyword can be applied to a constructor or (since C++11) a conversion operator, to ensure that it can only be used when the destination type is explicit at the point of use, ©.g. with a cast. This applies not only to implicit conversions, but to C++11's list initialization syntax: class Foo { explicit Foo(int x, double y); b void Func(Foo #); Func({42, 3.14}); // Error This kind of code isnt technically an implicit conversion, but the language treats it as one as far as explicit Is concemed, Pros: Implicit conversions can make a type more usable and expressive by eliminating the need to explicitly name a type when it's obvious. Implicit conversions can be a simpler altemative to overloading, List initialization syntax is a concise and expressive way of initializing objects, Cons: Implicit comersions can hide type-mismatch bugs, where the destination type does not match the user's expectation, or the user is unaware that any conversion will take place. + Implicit conversions can make code harder to read, particularly in the presence of ‘overloading, by making it less obvious what code is actually getting called. + Constructors that take a single argument may accidentally be usable as implicit type conversions, even if they are not intended to do so. + When a singlesargument constructor is not marked explicit, there's no reliable way to tell whether i's intended to define an implicit conversion, or the author simply forgot to mark it + It's not always clear which type should provide the conversion, and if they both do, the code becomes ambiguous. List initialization can suffer from the same problems if the destination type is implicit, particularly if the list has only a single element Decision: ‘Type conversion operators, and constructors that are callable with a single argument, must be marked explicit in the class definition. As an exception, copy and move constructors should not be explicit, since they do nol perform type conversion. Implicit conversions can sometimes be necessary and appropriate for types that are designed to transparently wrap other types. In that case, contact your project leads to request a waiver of this rule. Constructors that cannot be called with a single argument should usually omit explicit, Constructors that take a single std: : initializer_list parameter should also omit explicit, in order to support copy- initialization (e.g. MyType m = {1, 2}5) ©Copyable and Movable Types ‘Support copying andlor moving if these operations are clear and meaningful for your type, Othemwise, disable the implicitly generated special functions that perform copies and moves, hpsuigoogle.g iu fs uidecrpgul de hit sa. ezeotr Google C++ Syle Guide Definition: A copyable type allows its objects to be initialized or assigned ftom any other object of the same type, without changing the value of the source. For user-defined types, the copy behavior is defined by the copy constructor and the copy-assignment operator. string is an example of a copyable type. ‘A movable type is one that can be initialized and assigned from temporaries (all copyable types are therefore movable). std: :unique_ptr is an example of a movable but not copyable type. For user-defined types, the move behavior is defined by the move constructor and the move-assignment operator. ‘The copy/move constructors can be e.g. when passing objects by value. plcitly invoked by the compiler in some situations, Pros: Objects of copyable and movable types can be passed and retumed by value, which makes APIs simpler, Safer, and more general. Unlike when passing objects by pointer or reference, there's no risk of confusion over ownership, lifetime, mutability, and similar issues, and no heed to specify them in the contract. it also prevents non-ocal interactions between the client and the implementation, which makes them easier to understand, maintain, and optimize by the compiler. Further, such objects can be used with generic APIs that require pass-by-value, such as most containers, and they allow for additional flexibility in e.g., type composition Copy/move constructors and assignment operators are usually easier to define correctly than alternatives like Clone(), CopyFrom() or Swap(), because they can be generated by the compiler, either implicitly or with = default. They are concise, and ensure that all data members are copied. Copy and move constructors are also generally more eficient, because they dontt require heap allocation or separate initialization and assignment steps, and they're eligible for optimizations such as copy elision. Move operations allow the implicit and efficient transfer of resources out of rvalue objects. This allows a plainer coding style in some cases. Cons: ‘Some types do not need to be copyable, and providing copy operations for such types can be confusing, nonsensical, or outright incorrect. Types representing singleton objects (Registerer), objects tied to a specific scope (Cleanup), or closely coupled to object, identity (Mutex) cannot be copied meaningfully. Copy operations for base class types that are to be used polymorphically are hazardous, because use of them can lead to object slicing. Defaulted or carelessly-implemented copy operations can be incorrect, and the resulting bugs ‘can be confusing and dificult to diagnose. Copy constructors are invoked implicitly, which makes the invocation easy to miss. This may cause confusion for programmers used to languages where pass-by-reference is conventional or mandatory. It may also encourage excessive copying, which can cause performance problems, Decision: Provide the copy and mave operations if their meaning is clear to a casual user and the copying/moving does not incur unexpected costs. If you define a copy or move constructor, define the corresponding assignment operator, and vice-versa. If your type is copyable, do not define move operations unless they are significantly more efcient than the corresponding copy operations. tf your type is not copyable, but the correctness of a move is obvious to Users of the type, you may make the type move-only by defining both of the move operations. lf your type provides copy operations, it is recommended that you design your class so that the default implementation of those operations is correct. Remember to review the correctness of any defaulted operations as you would any other code, and to document that your class is copyable and/or cheaply movable if that's an API guarantee. hpsuigoogle.g iu fs uidecrpgul de hit 1895 ezeotr Google C++ Sle Guide class Foo { public: Foo(Foo8& other) : field_(other.field) {} // Bad, defines only nove constructor, but not operators. private: Field field; b Due to the risk of slicing, avoid providing an assignment operator or public copy/move constructor for a class that's intended to be derived from (and avoid deriving from a class with such members). f your base class needs to be copyable, provide a public virtual Clone() method, and a protected copy constructor that derived classes can use to implement IF you do not want to support copy/move operations on your type, explicitly disable them using = delete in the public: section // MyClass is neither copyable nor movable. MyClass(const MyClass&) = delete; MyClass& operator=(const MyClass) = delete; ©Structs vs. Classes Use a struct only for passive objects that carry data; everything else is a class. The struct and class keywords behae almost identically in C++. We add our own semantic meanings to each keyword, so you should use the appropriate keyword for the datatype you're defining structs should be used for passive objects that carry data, and may have associated constants, but lack any functionality other than access/setting the data members, The accessing/setting of fields is done by directly accessing the fields rather than through method invocations. Methods should not provide behavior but should only be used to set up the data members, ¢.g., constructor, destructor, Initialize(), Reset(), Validate‘), | more functionality is required, a class is more appropriate. ifin doubt, make it a class. For consistency with STL, you can use struct instead of class for functors and traits. Note that member variables in structs and classes have different naming rules. Inheritance Composition is often more appropriate than inheritance. When using inheritance, make it public. Definition: When a sub-class inherits from a base class, it includes the definitions of all the data and operations that the parent base class defines. In practice, inheritance is used in two major ‘ways in C++: implementation inheritance, in which actual code is inherited by the child, and Interface inheritance, in which only method names are inherited. hpsuigoogle.g iu fs uidecrpgul de hit 1818 ezeotr Google C++ Syle Guide Pros: Implementation inheritance reduces code size by re-using the base class code as it specializes an existing type. Because inheritance is a compile-time declaration, you and the compiler can understand the operation and detect errors. Interface inheritance can be used to programmatically enforce that a class expose a particular API. Again, the compiler can detect errors, in this case, when a class does not define a necessary method of the APL Cons: For implementation inheritance, because the code implementing a sub-class is spread between the base and the sub-class, it can be more difficult to understand an implementation. The sub-class cannot override functions that are not virtual, so the sub-class cannot change implementation, The base class may also define some data members, so that specifies physical layout of the base class. Decision: Alllinheritance should be public. If you want to do private inheritance, you should be including an instance of the base class as a member instead. Do not overuse implementation inheritance. Composition is often more appropriate. Try to restrict use of inheritance to the "is-a" case: Bar subclasses Foo ifit can reasonably be said that Bar "is a kind of" Foo. Make your destructor virtual if necessary. If your class has virtual methods, its destructor should be virtual Limit the use of protected to those member functions that might need to be accessed from Subclasses. Note that data members should be private, Explicitly annotate overrides of vitual functions or virtual destructors with an override or (less frequently) final specifier. Older (pre-C++11) code will use the virtual keyword as an inferior altemative annotation. For clarity, use exactly one of override, final, or virtual ‘when declaring an override. Rationale: A function or destructor marked override or final that is not an override of a base class virtual function will not compile, and this helps catch ‘common errors. The specifiers serve as documentation; if no specifier is present, the reader has to check all ancestors of the class in question to determine ifthe function or destructor is Virtual or not. Multiple Inheritance Only very rarely is multiple implementation inheritance actually useful. We allow multiple inheritance only when at most one of the base classes has an implementation; all other base classes must be pure interface classes tagged with the Interface suffix, Definition: Multiple inheritance allows a sub-class to have more than one base class. We distinguish between base classes that are pure interfaces and those that have an implementation. Pros: Muttiple implementation inheritance may let you re-use even more code than single inheritance (see Inheritance). Cons: hpsuigoogle.g iu fs uidecrpgul de hit sm. ezeotr Google C++ Syle Guide Only very rarely is multiple implementation inheritance actually useful. When multiple implementation inheritance seems like the solution, you can usually find a different, more explicit, and cleaner solution. Decision: Multiple inheritance is allowed only when all superclasses, with the possible exception of the first one, are pure interfaces. In order to ensure that they remain pure interfaces, they must lend with the Interface suffix Note: ‘There is an exception to this rule on Windows. Interfaces Classes that salisfy certain conditions are allowed, but not required, to end with an Interface suflx. Definition: ‘A class is a pure interface ifit meets the following requirements: + Ithas only public pure virtual ( destructor). + It may not have non-static data members, + It need not have any constructors defined. Ifa constructor is provided, it must take no arguments and it must be protected, + Ifitis a subclass, it may only be derived from classes that satisfy these conditions and are tagged with the Interface suffix. @") methods and static methods (but see below for An interface class can never be directly instantiated because of the pure virtual method(s) it declares. To make sure all implementations of the interface can be destroyed correctly, the Interface must also declare a Virtual destructor (in an exception to the first rule, this should not be pure). See Stroustrup, The C++ Programming Language, 3rd edition, section 12.4 for details Pros: Tagging a class with the Interface suffix lets others know that they must not add implemented methods or non static data members, This is particularly important in the case cf multiple inheritance, Additionally, the interface concept is already well-understood by Java programmers. Cons: The Interface suffix lengthens the class name, which can make it harder to read and Understand. Also, the interface property may be considered an implementation detail that shouldn't be exposed to clients. Decision: Acclass may end with Interface only ifit meets the above requirements. We do not require the converse, however: classes that meet the above requirements are not required to end with Interface. hpsuigoogle.g iu fs uidecrpgul de hit 1095. ezeotr Google C++ Syle Guide ©°Operator Overloading Overload operators judiciously. Do not create user-defined literals. Definition: C++ permits user code to declare overloaded versions of the builtin operators using the operator keyword, so long as one of the parameters is a user-defined type. The operator. keyword also permits user code to define new kinds of literals using operator”, and to define type-comversion functions such as operator bool() Pros: Operator overloading can make code more concise and intuitive by enabling user-defined types to behave the same as builtin types. Overloaded operators are the idiomatic names for certain operations (e.g. ==, <, =, and <<), and adhering to those conventions can make user- defined types more readable and enable them to interoperate with libraries that expect those names, User-defined literals are a very concise notation for creating objects of user-defined types. Cons: + Providing a correct, consistent, and unsurprising set of operator overloads requires ‘some care, and failure to do so can lead to confusion and bugs. + Overuse of operators can lead to obfuscated code, particulary if the overloaded ‘operator's semantics dont follow convention. + The hazards of function overloading apply just as much to operator overloading, if not more so. + Operator overloads can fool our intuition into thinking that expensive operations are ‘cheap, builtin operations. ‘+ Finding the call sites for overloaded operators may require a search tool that's aware of (G+ syntax, rather than e.g. grep. + Ifyou get the argument type of an overloaded operator wrong, you may get a different ‘overfoad rather than a compiler error, For example, foo < bar may do one thing, while &foo < &bar does something totally different, + Certain operator overloads are inherently hazardous. Overloading unary & can cause the same code to have different meanings depending on whether the overload declaration is vsible. Overioads of &8, ||, and , (comma) cannot match the evalvation-order semantics of the built4n operators. + Operators are often defined outside the class, so there's a risk of different files, introducing different definitions of the same operator. If both definitions are linked into the same binary, this results in undefined behavior, which can manifest as subtle rur- time bugs. + User-defined literals allow the creation of new syntactic forms that are unfamiliar even to experienced C++ programmers. Decision: Define overloaded operators only if their meaning is obvious, unsurprising, and consistent with the corresponding built-in operators. For example, use | as a bitwise- or logical-or, not as a shell-style pipe. Define operators only on your own types. More precisely, define them in the same headers, cc files, and namespaces as the types they operate on. That way, the operators are available wherever the type is, minimizing the risk of multiple definitions. if possible, avoid defining operators as templates, because they must satisfy this rule for any possible template arguments. If you define an operator, also define any related operators that make sense, and make sure they are defined consistently. For example, if you overload <, overload. hpsuigoogle.g iu fs uidecrpgul de hit 1975 ezeotr Google C++ Syle Guide all the comparison operators, and make sure < and > never retum true for the same arguments. Prefer to define non-modifying binary operators as non-member functions. Ifa binary operator is defined as a class member, implicit conversions will apply to the right-hand argument, but not the left-hand one. It wll confuse your users ifa < b compiles but b < a doesnt. Don't go out of your way to avoid defining operator overloads. For example, prefer to define and <<, rather than Equals(), CopyFrom(), and PrintTa(). Conversely, don't define operator overloads just because other libraries expect them. For example, if your type doesnt have a natural ordering, but you want to store it in a std: :set, use a custom comparator rather than overloading < Do not overioad 88, ||, , (comma), or unary &, Do not overload operator’ introduce user-defined literals, ie, do not Type conversion operators are covered in the section on implicit conversions. The = operator is covered in the section on copy constructors. Overloading << for use with streams is covered in the section on streams. See also the rules on function overloading, which apply to operator overloading as well °° Access Control Make data members private, unless they are static const (and follow the naming convention for constants). For technical reasons, we allow data members of a test fixture class to be protected when using Google Test). °°Declaration Order Group similar declarations together, placing public parts earlier, A class definition should usually start with a public: section, followed by protected:, then private:, Omit sections that would be empty. Within each section, generally prefer grouping similar kinds of declarations together, and generally prefer the following order: types (including typedef, using, and nested structs and classes), constants, factory functions, constructors, assignment operators, destructor, all other methods, data members. Do not put large method definitions inline in the class definition. Usually, only trival or performance-critical, and very short, methods may be defined inline. See Inline Functions for more details. °°Functions ©°Parameter Ordering hpsuigoogle.g iu fs uidecrpgul de hit as ezeotr Google C++ Syle Guide When defining a function, parameter order is: inputs, then outputs, Parameters to C/C++ funetions are either input to the function, output from the function, or both, Input parameters are usually values or const references, while output and input/output, parameters will be pointers to non-const. When ordering function parameters, put all input- only parameters before any output parameters. In particular, do not add new parameters to the end of the function just because they are new, place new input-only parameters before the output parameters. This is not a hard-andfast rule, Parameters that are both input and output (often classes/structs) muddy the waters, and, as always, consistency with related functions may require you to bend the rule, °°Write Short Functions Prefer small and focused functions. We recognize that long functions are sometimes appropriate, so no hard limit is placed on functions length, Ifa function exceeds about 40 lines, think about whether it can be broken up ‘without harming the structure of the program, Even if your long function works perfectly now, someone modifying it in a few months may ‘add new behavior, This could result in bugs that are hard to find, Keeping your functions short and simple makes it easier for other people to read and modify your code, You could find long and complicated functions when working with some code. Do not be intimidated by modifying existing code: if working with such a function proves to be dificult, you find that errors are hard to debug, or you want to use a piece of it in several diferent Contexts, consider breaking up the function into smaller and more manageable pieces, ©°Reference Arguments Al parameters passed by reference must be labeled const. Definition: In C, ifa function needs to modify a variable, the parameter must use a pointer, eg int foo(int *pval). In C++, the function can alteratively declare a reference parameter: int foo(int aval). Pros: Defining a parameter as reference avoids ugly code like (*pval) ++. Necessary for some applications like copy constructors. Makes it clear, unlike with pointers, that a null pointer is not a possible value. Cons: References can be confusing, as they have value syntax but pointer semantics, Decision: Within function parameter lists all references must be const: hpsuigoogle.g iu fs uidecrpgul de hit 2s ezeotr Google C++ Sle Guide void Foo(const string &in, string tout); In fact tis a very strong convention in Google code that input arguments are values of const relerences vile oulput arguments are pointers. Input parameters may be const pointers, but wwe never allow non-const reference parameters except when required by comertion, e.g. s0ap() However, there are some instances where using const T* is preferable to const T& for input parameters. For example: + You want to pass in a null pointer, + The function saves a pointer or reference to the input Remember that most of the time input parameters are going to be specified as const T&. Using const T* instead communicates to the reader that the input is somehow treated differently. So if you choose const T* rather than const T&, do so for a concrete reason; othenvise it will kely confuse readers by making them look for an explanation that doesn't exist. ©°Function Overloading Use overloaded functions (including constructors) only ifa reader looking at a call site can get 1a good idea of what is happening without having to fist figure out exactly which overload is being called. Definition: ‘You may write a function that takes a const. string& and overload it with another that takes const char*, class MyClass ( public: void Analyze(const string atext); void Analyze(const char *text, size_t textlen); Pros: COverfoading can make code more intuitive by allowing an identically-named function to take diferent arguments. It may be necessary for templatized cade, and it can be convenient for Visitors, Cons: Ifa function is overloaded by the argument types alone, a reader may have to understand (C++'s complex matching rules in order to tell what's going on. Also many people are confused by the semantics of inheritance if a derived class overrides only some of the variants of a function. Decision: you want to overload a funetion, consider qualifying the name with some information about the arguments, e.g., AppendStriing(), AppendInt () rather than just Append(). If you are overloading a function to support variable number of arguments of the same type, consider ‘making it take a std: :vector so that the user can use an initializer list to specify the arguments. hpsuigoogle.g iu fs uidecrpgul de hit ans ezeotr Google C++ Syle Guide °°Default Arguments Default arguments are allowed on non-virtual functions when the default is guaranteed to always have the same value. Follow the same restrictions as for function overloading, and prefer overloaded functions if the readability gained with default arguments doesnt outweigh the downsides below, Pros: (Often you have a function that uses default values, but occasionally you want to override the defaulls. Default parameters allow an easy way to do this without having to define many functions for the rare exceptions. Compared to overloading the function, default arguments have a cleaner syntax, with less boilerplate and a clearer distinction between ‘required’ and ‘optional’ arguments. Cons: Defaulted arguments are another way to achieve the semantics of overloaded functions, so all the reasons not to overload functions apply. ‘The defaults for arguments in a virtual function call ae determined by the static type of the target object, and there's no guarantee that all overrides of a given function declare the same defaults Default parameters are re-evaluated at each call site, which can bloat the generated code Readers may also expect the defaul’s value to be fixed al the declaration instead of varying at each call Function pointers are confusing in the presence of default arguments, since the function signature often doesnt match the call signature. Adding function overloads avoids these problems. Decision: Default arguments are banned on virtual functions, where they don't work properly, and in cases where the specified default might not evaluate to the same value depending on when it was evaluated. (For example, dont write void #(int n = counter++);.) In some other cases, default arguments can improve the readability oftheir function declarations enough to overcome the downsides above, so they are allowed. When in doubt, use overloads. Trailing Return Type Syntax Use trailing retum types only where using the ordinary syntax (leading retum types) is impractical or much less readable. Definition: C++ allows two different forms of function declarations. In the older form, the retum type appears before the function name, For example: int foo(int x); hpsuigoogle.g iu fs uidecrpgul de hit 208 ezeotr Google C++ Syle Guide The new form, introduced in C++11, uses the auto keyword before the function name and a trailing retum type atter the argument list. For example, the declaration above could equivalently be written: auto foo(int x) -> ints The trailing return type is in the function's scope. This doesn't make a difference for a simple case like int but it matters for more complicated cases, like types declared in class scope or types written in terms of the function parameters. Pros: ‘Trailing retum types are the only way to explicitly specify the return type of a lambda expression. In some cases the compiler is able to deduce a lambda's retum type, but not in all cases. Even when the compiler can deduce it automatically, sometimes specifying it explicitly would be clearer for readers. ‘Sometimes it's easier and more readable to specify a return type afer the function's parameter list has already appeared. This is particularly true when the retum type depends on template parameters. For example: template auto add(T t, U u) -> decltype(t + u); versus template decltype(declval() + declval()) add(T t Cons: ‘Trailing retum type syntax is relatively new and it has no analogue in C++-like languages like. Cand Java, so some readers may find it unfamiliar, Existing cade bases have an enormous number of function declarations that arent going to get changed to use the new syntax, so the realistic choices are using the old syntax only or Using a mixture of the two. Using a single version is better for uniformity of style. Decision: In most cases, continue to use the older style of function declaration where the retum type goes before the function name, Use the new trailing-retum-type form only in cases where it's required (Such as lambdas) or where, by putting the type after the function's parameter lst, it allows you to write the type in a much more readable way. The latter case should be rare; i's mostly an issue in faiy complicated template code, which is discouraged in most cases, °°Google-Specific Magic There are various tricks and utilities that we use to make C++ code more robust, and various ways we use C++ that may difler from what you see elsewhere, °°Ownership and Smart Pointers hpsuigoogle.g iu fs uidecrpgul de hit 2408 ezeotr Google C++ Syle Guide Prefer to have single, fixed owners for dynamically allocated objects. Prefer to transfer ‘ownership with smart pointers. Definition: nership” is a bookkeeping technique for managing dynamically allocated memory (and other resources). The owner of a dynamically allocated object is an object or function that is. responsible for ensuring that it is deleted when no longer needed. Ownership can sometimes be shared, in which case the last owner is typically responsible for deleting it. Even when ownership is not shared, it can be transferred from one piece of code to another. “Smart” pointers are classes that act like pointers, e.g. by overloading the * and -> operators. Some smart pointer types can be used to automate ownership bookkeeping, to ensure these responsibilities are met. std: unique ptr is a smart pointer type introduced in C+#11, which expresses exclusive ownership of a dynamically allocated object; the object is deleted when the std: :unique_ptr goes out of scope. It cannot be copied, but can be ‘moved to represent ownership transfer, std: :shared_ptr: is a smart pointer type that expresses shared ownership of a dynamically allocated object. std: :shared_ptrs can be copied; ownership of the object is shared among all copies, and the object is deleted when the last std::shared_ptr is destroyed. Pros: + It's vitually impossible to manage dynamically allocated memory without some sort of ‘ownership logic. + Transferring ownership of an object can be cheaper than copying it (copying itis even possible). + Transferring ownership can be simpler than ‘borrowing! a pointer or reference, because it reduces the need to coordinate the lifetime of the object between the two users. + Smart pointers can improve readability by making ownership logic explicit, self documenting, and unambiguous. + Smart pointers can eliminate manual ownership bookkeeping, simplifying the code and ruling out large classes of errors. + For const objects, shared ownership can be a simple and efficient alternative to deep copying. Cons: + Ownership must be represented and transferred via pointers (whether smart or plain), Pointer semantics are more complicated than value semantics, especially in APIs: You have to worry not just about ownership, but also aliasing, lifetime, and mutability, ‘among other Issues. + The performance costs of value semantics are often overestimated, so the performance benefits of ownership transfer might not justify the readability and complexity costs, + APIs that transfer ownership force their clients into a single memory management model, + Code using smart pointers is less explicit about where the resource releases take place. + std: :unique_ptr expresses ownership transfer using C+#11's move semantics, which are relatively new and may confuse some programmers. + Shared ownership can be a tempting altemative to careful ownership design, ‘obfuscating the design of a system. ‘+ Shared ownership requires explicit bookkeeping at run-time, which can be costly. + Insome cases (0.9. cyclic references), objects with shared ownership may never be deleted. ‘Smart pointers are not perfect substitutes for plain pointers. Decision: dynamic allocation is necessary, prefer to keep ownership with the code that allocated it. If other code needs access to the object, consider passing It a copy, or passing a pointer or hpsuigoogle.g iu fs uidecrpgul de hit 28 ezeotr Google C++ Syle Guide reference without transferring ownership, Prefer to use std: :unique_ptr to make ownership transfer explicit. For example: std: :unique_ptr FooFactory(); void FooConsuner(std: :unique_ptr ptr); Do not design your code to use shared ownership without a very good reason. One such reason is to avoid expensive copy operations, but you should only do this if the performance benefits are significant, and the underlying object is immutable (i.<. std::shared_ptr, for example, then auto v2(std: :move(v1)) will probably just result in some simple pointer manipulation instead of copying a large amount of data, In some cases this can result in a major performance improvement, ‘+ Rialue references make it possible to write a generic function wrapper that forwards its ‘arguments to another function, and works whether or not its arguments are temporary hpsuigoogle.g iu fs uidecrpgul de hit 2608 ezeotr Google C++ Syle Guide ‘objects. (This is sometimes called "perfect forwarding".) + Rialue references make it possible to implement types that are movable but not copyable, which can be useful for types that have no sensible definition of copying but where you might stil want to pass them as function arguments, put them in containers, et. + std: :move is necessary to make effective use of some standardJibrary types, such unique_ptr. + Rialue references are a relatively new feature (introduced as part of C++11), and not yet widely understood. Rules like reference collapsing, and automatic synthesis of move constructors, are complicated. Decision: Use rvalue references only to define move constructors and move assignment operators (as described in Copyable and Movable Types) and, in conjunction with std: :forward, to Support perfect forwarding. You may use std: :move to express moving a value from one: object to another rather than copying it. ° Friends We allow use of friend classes and functions, within reason. Friends should usually be defined in the same flle so that the reader does not have to look in another file to find uses of the priate members of a class. A common use of friend is to have a FooBuilder class be a friend of Foo so that it can construct the inner state of Foo correctly, without exposing this state to the world. In some cases it may be useful to make a unittest class a friend of the class it tests. Friends extend, but do not break, the encapsulation boundary of a class. In some cases this is better than making a member public when you want to give only one other class access to it, However, most classes should interact with other classes solely through their public members. °° Exceptions We do not use C++ exceptions. Pros: + Exceptions allow higher levels of an application to decide how to handle "can't happen” failures in deeply nested functions, without the obscuring and error-prone bookkeeping of error codes. ‘+ Exceptions are used by most other modem languages. Using them in C++ would make it more consistent with Python, Java, and the C++ that others are familiar with, + Some third-party C++ libraries use exceptions, and tuning them off intemally makes it harder to integrate with those libraries, + Exceptions are the only way for a constructor to fal. We can simulate this with a factory function or an Init() method, but these require heap allocation or a new “imalia” state, respectively, + Exceptions are really handy in testing frameworks, hpsuigoogle.g iu fs uidecrpgul de hit ams ezeotr Google C++ Syle Guide Cons: + When you add a throw statement to an existing function, you must examine all ofits transitive callers. Either they must make at least the basic exception safety ‘uarantee, or they must never catch the exception and be happy with the program terminating as a result. For instance, i €() calls g() calls h(), and h throws an ‘exception that f catches, g has to be careful orit may not clean up property + More generally, exceptions make the control low of programs dificult to evaluate by looking at code: functions may retum in places you dontt expect. This causes maintainability and debugging diffculties. You can minimize this cost va some rules ‘on how and where exceptions can be used, but at the cost of more that a developer needs to know and understand. + Exceplion safety requires both RAll and diferent coding practices. Lots of supporting machinery is needed to make writing correct exceplion-safe code easy. Further, to ‘avoid requiring readers to understand the entire call graph, exception-safe code must isolate logic that writes to persistent state into a "commit" phase. This will have both benefits and costs (perhaps where you's forced to obfuscate code to isolate the commit). Allowing exceptions would force us to always pay those costs even when they're not worth it + Tuming on exceptions adds data to each binary produced, increasing compile time (probably slightly) and possibly increasing address space pressure. + The availabilty of exceptions may encourage developers to throw them when they are not appropriate or recover from them when its not safe to do so. For example, invalid user input should not cause exceptions to be thrown, We would need to make the style guide even longer to document these restrictions! Decision: (On their face, the benefits of using exceptions outweigh the costs, especially in new projects. However, for existing code, the introduction of exceptions has implications on all dependent code. If exceptions can be propagated beyond a new project, it also becomes problematic to integrate the new project into existing exception-ree code. Because most existing C++ code at Google is not prepared to deal with exceptions, it is comparatively dificult to adopt new code that generates exceptions. Given that Google's existing code is not exception-tolerant, the costs of using exceptions are somewhat greater than the costs in a new project. The conversion process would be slow and error-prone, We don't believe that the available altematives to exceptions, such as error codes. and assertions, introduce a significant burden. ‘Our advice against using exceptions is not predicated on philosophical or moral grounds, but practical ones. Because we'd like to use our open-source projects at Google and it’s dificult to do so if those projects use exceptions, we need to advise against exceptions in Google open-source projects as well. Things would probably be different if we had to do it all over again ftom scratch, This prohibition also applies to the exceptionelated features added in C+#11, such as noexcept, std: :exception_ptr, and std: :nested_exception There is an exception to this rule (no pun intended) for Windows code. Run-Time Type Information (RTT!) Avoid using Run Time Type Information (RTT). Definition: hpsuigoogle.g iu fs uidecrpgul de hit ezeotr Google C++ Syle Guide RTT allows a programmer to query the C++ class of an object at run time. This is done by se of typeid or dynamic_cast. Cons: Querying the type of an object at run-time frequently means a design problem. Needing to know the type of an object at runtime is often an indication that the design of your class hierarchy is flawed Undisciplined use of RTTI makes code hard to maintain. It can lead to type-based decision trees or switch statements scattered throughout the code, all of which must be examined ‘when making further changes. Pros: The standard altematives to RTTI (described below) require modification or redesign of the class hierarchy in question. Sometimes such modifications are infeasible or undesirable, particularly in widely-used or mature code, RTT can be uselul in some unit tests. For example, itis useful in tests of factory classes where the test has to verify that a newly created object has the expected dynamic type. It is also useful in managing the relationship between objects and their mocks. RTTis useful when considering multiple abstract objects. Consider bool Base: :Equal(Base* other) = @; bool Derived: :Equal(Base* other) ( Derived* that = dynamic_cast(other) ; if (that == NULL) return false; Decision: RTT has legitimate uses but is prone to abuse, so you must be careful when using it. You may use it freely in unittests, but avoid it when possible in other code. In particular, think twice before using RTI in new code, If you find yourself needing to write code that behaves diflerently based on the class of an object, consider one of the following altematives to querying the type: + Virtual methods are the preferred way of executing different code paths depending on a specific subclass type. This puts the work within the object itself. + Ifthe work belongs outside the abject and instead in some processing code, consider ‘a double-dispatch solution, such as the Visitor design pattem. This allows a facility ‘outside the object itself to determine the type of class using the built-in type system. When the logic of a program guarantees that a given instance of a base class is in fact an instance of a particular derived class, then a dynamic_cast may be used freely on the object. Usually one can use a static_cast as an altemative in such situations. Decision trees based on type are a strong indication that your code is on the wrong track. if (typeid(*data) typeid(D1)) ( } else iF (typeid(tdata) == typeid(o2)) { } else if (typeid(*data) == typeid(03)) { Code such as this usually breaks when additional subclasses are added to the class hierarchy. Moreover, when properties of a subclass change, itis diffcult to find and modify all hpsuigoogle.g iu fs uidecrpgul de hit as ezeotr Google C++ Syle Guide the affected code segments, Do not hand-implement an RTTHike workaround, The arguments against RTTI apply just as much to workarounds like class hierarchies with type tags. Moreover, workarounds disguise your true intent. °°casting Use C++-style casts like static_cast(double_value), or brace initialization for conversion of arithmetic types Iké intéa y = int64{1} << 42. Donat use cast formats like int y = (int)x or int y = int(x) (but the latter is okay when invoking a constructor of a class type) Definition: C++ introduced a different cast system ftom C that distinguishes the types of cast operations, Pros: The problem with C casts is the ambiguity of the operation; sometimes you are doing a conversion (e.g., (4nt)3-5) and sometimes you are doing a cast (e.g., (int)"hello"). Brace initialization and C++ casts can often help avoid this ambiguity. Additionally, C++ casts are more visible when searching for them. Cons: The C++-style cast syntax is verbose and cumbersome, Decision: Do not use C-style casts. Instead, use these C++-style casts when explicit type conversion is necessary. + Use brace initialization to convert arithmetic types (e.g. int64(x}), This is the safest approach because code will not compile if conversion can result in information loss. ‘The syntax is also concise, + Use static_cast as the equivalent of a C-style cast that does value conversion, when you need to explicitly up-cast a pointer from a class to its superclass, or when you need to explicitly cast a pointer from a superclass to a subclass. in this last case, you must be sure your object is actually an instance of the subclass. + Use const_cast to remove the const qualifier (see const). + Use reinterpret_cast to do unsafe conversions of pointer types to and from integer and other pointer types. Use this only if you know what you are doing and you Understand the aliasing issues. ‘See the RTI section for guidance on the use of dynamic_cast. ° Streams Use streams where appropriate, and stick to "simple" usages. Definition: hpsuigoogle.g iu fs uidecrpgul de hit ars ezeotr Google C++ Syle Guide Streams are the standard (0 abstraction in C++, as exemplified by the standard header . They are widely used in Google code, but only for debug logging and test diagnostics. Pros: The << and >> stream operators provide an API for formatted VO that is easily learned, portable, reusable, and extensible. printf, by contrast, doesn't even support string, to say nothing of user-defined types, and is very difficult to use portably. printf also obliges you to choose among the numerous slightly different versions of that function, and navigate the dozens of conversion specifiers. Streams provide first-class support for console /O via std::cin, std::cout, std: :cern, and std: :clog, The C APIs do as well, but are hampered by the need to manually buffer the input, Cons: + Stream formatting can be configured by mutating the state of the stream. Such mutations are persistent, so the behavior of your code can be affected by the entire prevous history of the stream, unless you go out of your way to restore it to a known state every time other code might have touched it. User code can not only modify the builtin state, it can add new state variables and behaviors through a registration system, * Its diffcult to precisely control stream output, due to the above issues, the way code and data are mixed in streaming code, and the use of operator overloading (which may select a different overload than you expect), + The practice of building up output through chains of << operators interferes with intemationalization, because it bakes word order into the code, and streams’ support for localization is flawed. + The streams APIis subtle and complex, so programmers must develop experience with it in order to use it effectively. However, streams were historically banned in Google code (except for logging and diagnostics), so Google engineers tend not to have that experience. Consequently, streams-based code is likely to be less readable and maintainable by Googlers than code based on more familiar abstractions. + Resolving the many overtoads of << is extremely costly for the compiler, When used penasively in a large code base, it can consume as much as 20% of the parsing and ‘semantic analysis time, Decision: Use streams only when they are the best tool for the job. This is typically the case when the VO is ad-hoc, local, human-readable, and targeted at other developers rather than end-users, Be consistent with the cade around you, and with the codebase as a whole; if there's an established tool for your problem, use that tool instead. ‘Avoid using streams for V/O that faces extemal users or handles untrusted data. Instead, find and use the appropriate templating libraries to handle issues like interiationalization, localization, and security hardening. you do use streams, avoid the stateful parts of the streams API (other than error state), such as inbue(), xalloc(), and register_callback(). Use explicit formatting functions rather than stream manipulators or formatting flags to control formatting details such as number base, precision, or padding. Overload << as a streaming operator for your type only if your type represents a value, and << ‘writes out a human-readable string representation ofthat value. Avoid exposing implementation details in the output of <<; if you need to print object internals for debugging, Use named functions instead (a method named DebugString() is the most common convention). hpsuigoogle.g iu fs uidecrpgul de hit sus ezeotr Google C++ Syle Guide °°Preincrement and Predecrement Use prefix form (++i) of the increment and decrement operators with iterators and other template objects. Definition: When a variable is incremented (+44 or i++) or decremented (--i or i--) and the value of the expression is not used, one must decide whether to preincrement (decrement) or postincrement (decrement). Pros: When the return value is ignored, the "pre" form (+4) is never less efficient than the "post" form (i++), and is often more eficient. This is because post-increment (or decrement) requires a copy of i to be made, which is the value of the expression. If i is an iterator or other non-scalar type, copying i could be expensive. Since the two types of increment behave the same when the value is ignored, why not just always pre-increment? Cons: The tradition developed, in C, of using post-increment when the expression value is not used, especially in for loops. Some find postincrement easier to read, since the "subject" (i) precedes the "verb" (++), just like in English. Decision: For simple scalar (non-object) values there is no reason to prefer one form and we allow either. For iterators and other template types, use pre-increment. Use of const Use const whenever it makes sense, With C++11, constexpr is a better choice for some uses of const. Definition: Declared variables and parameters can be preceded by the keyword const to indicate the variables are not changed (e.g., const int foo). Class functions can have the const qualifier to indicate the function does not change the state of the class. member variables (eg. class Foo { int Bar(char c) const; };} Pros: Easier for people to understand how variables are being used. Allows the compiler to do better type checking, and, conceivably, generate better code. Helps people convince themselves of program correctness because they know the funetions they call are limited in how they can modify your variables. Helps people know what functions are safe to use ‘without locks in multi-threaded programs. Cons: const is viral: if you pass a const variable to a function, that function must have const in its prototype (or the variable will need a const_cast). This can be a particular problem when, calling library functions. hpsuigoogle.g iu fs uidecrpgul de hit sans ezeotr Google C++ Syle Guide Decision: const \ariables, data members, methods and arguments add a level of compile-time type checking; it is better to detect errors as soon as possible. Therefore we strongly recommend that you use const whenever it makes sense to do so: + Ifa function guarantees that it wll not modify an argument passed by reference or by pointer, the corresponding function parameter should be a reference-to-const (const T&) or pointer-to-const (const T*), respectively. + Declare methods to be const whenever possible. Accessors should almost always be const. Other methods should be const if they do not modify any data members, do not call any non-const methods, and do not return a non-const pointer or non-const reference to a data member. + Consider making data members const whenever they do not need to be modified after construction ‘The mutable keyword is allowed but is unsafe when used with threads, so thread safety should be carefully considered first. Where to put the const ‘Some people favor the form int const *Foo to const int* foo. They argue that this is more readable because it's more consistent: it keeps the rule that const always follows the object i's describing. However, this consistency argument doesn't apply in codebases with few deeply-nested pointer expressions since most const expressions have only one const, and it applies to the underlying value, In such cases, there's no consistency to maintain Putting the const first is arguably more readable, since it follows English in putting the "adjective" (const) before the “noun" (int), ‘That said, while we encourage putting const frst, we do not require it. But be consistent with the code around you! ©°Use of constexpr In C+#11, use constexpr to define true constants or to ensure constant initialization. Definition: ‘Some variables can be declared constexpr to indicate the variables are true constants, i. fixed at compilation/link time. Some functions and constructors can be declared constexpr which enables them to be used in defining a constexpr variable. Pros: Use of constexpr enables definition of constants with floating-point expressions rather than just literals; definition of constants of user-defined types; and definition of constants with funetion calls, Cons: Prematurely marking something as constexpr may cause migration problems if later on it has to be downgraded. Current restrictions on what is allowed in constexpr functions and. constructors may invite obscure workarounds in these definitions. Decision: hpsuigoogle.g iu fs uidecrpgul de hit sas

You might also like