From 3591b2e540cbcb07423e02d20eee482165776603 Mon Sep 17 00:00:00 2001 From: Geoff Romer Date: Fri, 11 Sep 2015 15:09:00 -0700 Subject: [PATCH] Update C++ Style Guide to 4.177. --- cppguide.html | 2278 ++++++++++++++++++++++++++++--------------------- 1 file changed, 1289 insertions(+), 989 deletions(-) diff --git a/cppguide.html b/cppguide.html index f517fde..0195cec 100644 --- a/cppguide.html +++ b/cppguide.html @@ -32,36 +32,133 @@ the conventions that govern our C++ code. The term Style is a bit of a misnomer, since these conventions cover far more than just source file formatting.

-

One way in which we keep the code base manageable is by -enforcing consistency. It is very -important that any -programmer be able to look at -another's code and quickly understand it. Maintaining a uniform -style and following conventions means that we can more easily -use "pattern-matching" to infer what various symbols are and -what invariants are true about them. Creating common, required -idioms and patterns makes code much easier to understand. In -some cases there might be good arguments for changing certain -style rules, but we nonetheless keep things as they are in -order to preserve consistency.

+

+Most open-source projects developed by +Google conform to the requirements in this guide. +

-

Another issue this guide addresses is that of C++ feature -bloat. C++ is a huge language with many advanced features. In -some cases we constrain, or even ban, use of certain features. -We do this to keep code simple and to avoid the various common -errors and problems that these features can cause. This guide -lists these features and explains why their use is -restricted.

-

Open-source projects -developed by Google conform to the requirements in this -guide.

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

+

Goals of the Style Guide

+
+

Why do we have this document?

+ +

There are a few core goals that we believe this guide should +serve. These are the fundamental whys that +underlie all of the individual rules. By bringing these ideas to +the fore, we hope to ground discussions and make it clearer to our +broader community why the rules are in place and why particular +decisions have been made. If you understand what goals each rule is +serving, it should be clearer to everyone when a rule may be waived +(some can be), and what sort of argument or alternative would be +necessary to change a rule in the guide.

+ +

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

+
+
Style rules should pull their weight
+
The benefit of a style rule +must be large enough to justify asking all of our engineers to +remember it. The benefit is measured relative to the codebase we would +get without the rule, so a rule against a very harmful practice may +still have a small benefit if people are unlikely to do it +anyway. This principle mostly explains the rules we don’t have, rather +than the rules we do: for example, goto contravenes many +of the following principles, but is already vanishingly rare, so the Style +Guide doesn’t discuss it.
+ +
Optimize for the reader, not the writer
+
Our codebase (and most individual components submitted to it) is +expected to continue for quite some time. As a result, more time will +be spent reading most of our code than writing it. We explicitly +choose to optimize for the experience of our average software engineer +reading, maintaining, and debugging code in our codebase rather than +ease when writing said code. "Leave a trace for the reader" is a +particularly common sub-point of this principle: When something +surprising or unusual is happening in a snippet of code (for example, +transfer of pointer ownership), leaving textual hints for the reader +at the point of use is valuable (std::unique_ptr +demonstrates the ownership transfer unambiguously at the call +site).
+ +
Be consistent with existing code
+
Using one style consistently through our codebase lets us focus on +other (more important) issues. Consistency also allows for +automation: tools that format your code or adjust +your #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" boil down to "Just pick one and +stop worrying about it"; the potential value of allowing flexibility +on these points is outweighed by the cost of having people argue over +them.
+ +
Be consistent with the broader C++ community when appropriate
+
Consistency with the way other organizations use C++ has value for +the same reasons as consistency within our code base. If a feature in +the C++ standard solves a problem, or if some idiom is widely known +and accepted, that's an argument for using it. However, sometimes +standard features and idioms are flawed, or were just designed without +our codebase's needs in mind. In those cases (as described below) it's +appropriate to constrain or ban standard features. In some cases we +prefer a homegrown or third-party library over a library defined in +the C++ Standard, either out of perceived superiority or insufficient +value to transition the codebase to the standard interface.
+ +
Avoid surprising or dangerous constructs
+
C++ has features that are more surprising or dangerous than one +might think at a glance. Some style guide restrictions are in place to +prevent falling into these pitfalls. There is a high bar for style +guide waivers on such restrictions, because waiving such rules often +directly risks compromising program correctness. +
+ +
Avoid constructs that our average C++ programmer would find tricky +or hard to maintain
+
C++ has features that may not be generally appropriate because of +the complexity they introduce to the code. In widely used +code, it may be more acceptable to use +trickier language constructs, because any benefits of more complex +implementation are multiplied widely by usage, and the cost in understanding +the complexity does not need to be paid again when working with new +portions of the codebase. When in doubt, waivers to rules of this type +can be sought by asking +your project leads. This is specifically +important for our codebase because code ownership and team membership +changes over time: even if everyone that works with some piece of code +currently understands it, such understanding is not guaranteed to hold a +few years from now.
+ +
Be mindful of our scale
+
With a codebase of 100+ million lines and thousands of engineers, +some mistakes and simplifications for one engineer can become costly +for many. For instance it's particularly important to +avoid polluting the global namespace: name collisions across a +codebase of hundreds of millions of lines are difficult to work with +and hard to avoid if everyone puts things into the global +namespace.
+ +
Concede to optimization when necessary
+
Performance optimizations can sometimes be necessary and +appropriate, even when they conflict with the other principles of this +document.
+
+ +

The intent of this document is to provide maximal guidance with +reasonable restriction. As always, common sense and good taste should +prevail. By this we specifically refer to the established conventions +of the entire Google C++ community, not just your personal preferences +or those of your team. Be skeptical about and reluctant to use +clever or unusual constructs: the absence of a prohibition is not the +same as a license to proceed. Use your judgment, and if you are +unsure, please don't hesitate to ask your project leads to get additional +input.

+ +
+

Header Files

@@ -150,84 +247,88 @@ guard:

Forward Declarations

-

You may forward declare ordinary classes in order to avoid -unnecessary #includes.

+

Avoid using forward declarations where possible. + Just #include the headers you need.

A "forward declaration" is a declaration of a class, -function, or template without an associated definition. -#include lines can often be replaced with -forward declarations of whatever symbols are actually -used by the client code.

+function, or template without an associated definition.

    -
  • Unnecessary #includes force the - compiler to open more files and process more - input.
  • +
  • Forward declarations can save compile time, as + #includes force the compiler to open + more files and process more input.
  • -
  • They can also force your code to be recompiled more - often, due to changes in the header.
  • +
  • Forward declarations can save on unnecessary + recompilation. #includes can force + your code to be recompiled more often, due to unrelated + changes in the header.
    -
  • It can be difficult to determine the correct form - of a forward declaration in the presence of features - like templates, typedefs, default parameters, and using - declarations.
  • +
  • Forward declarations can hide a dependency, allowing + user code to skip necessary recompilation when headers + change.
  • + +
  • A forward declaration may be broken by subsequent + changes to the library. Forward declarations of functions + and templates can prevent the header owners from making + otherwise-compatible changes to their APIs, such as + widening a parameter type, adding a template parameter + with a default value, or migrating to a new namespace.
  • + +
  • Forward declaring symbols from namespace + std:: yields undefined behavior.
  • It can be difficult to determine whether a forward - declaration or a full #include is needed - for a given piece of code, particularly when implicit - conversion operations are involved. In extreme cases, - replacing an #include with a forward + declaration or a full #include is needed. + Replacing an #include with a forward declaration can silently change the meaning of - code.
  • + code: +
          // b.h:
    +      struct B {};
    +      struct D : B {};
    +
    +      // good_user.cc:
    +      #include "b.h"
    +      void f(B*);
    +      void f(void*);
    +      void test(D* x) { f(x); }  // calls f(B*)
    +      
    + If the #include was replaced with forward + decls for B and D, + test() would call f(void*). +
  • Forward declaring multiple symbols from a header can be more verbose than simply #includeing the header.
  • -
  • Forward declarations of functions and templates can - prevent the header owners from making - otherwise-compatible changes to their APIs; for - example, widening a parameter type, or adding a - template parameter with a default value.
  • -
  • Forward declaring symbols from namespace - std:: usually yields undefined - behavior.
  • -
  • Structuring code to enable forward declarations (e.g. using pointer members instead of object members) can make the code slower and more complex.
  • -
  • The practical efficiency benefits of forward - declarations are unproven.
  • +
    +
  • Try to avoid forward declarations of entities + defined in another project.
  • +
  • When using a function declared in a header file, always #include that header.
  • When using a class template, prefer to #include its header file.
  • - -
  • When using an ordinary class, relying on a forward - declaration is OK, but be wary of situations where a - forward declaration may be insufficient or incorrect; - when in doubt, just #include the - appropriate header.
  • - -
  • Do not replace data members with pointers just to - avoid an #include.

Please see Names and Order @@ -291,32 +392,6 @@ mutators.

-

Function Parameter Ordering

- -
-

When defining a function, parameter order is: inputs, then -outputs.

-
- -
-

Parameters to C/C++ functions are either input to the -function, output from the function, or both. Input -parameters are usually values or const -references, while output and input/output parameters will -be non-const pointers. When ordering -function parameters, put all input-only parameters before -any output parameters. In particular, do not add new -parameters to the end of the function just because they -are new; place new input-only parameters before the -output parameters.

- -

This is not a hard-and-fast rule. Parameters that are -both input and output (often classes/structs) muddy the -waters, and, as always, consistency with related -functions may require you to bend the rule.

- -
-

Names and Order of Includes

@@ -381,8 +456,8 @@ 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 cases of forward -declaration). If you rely on symbols from bar.h, +upon, except in the unusual case of forward +declaration. If you rely on symbols from bar.h, don't count on the fact that you included foo.h which (currently) includes bar.h: include bar.h yourself, unless foo.h explicitly demonstrates its intent @@ -430,12 +505,11 @@ system-specific code small and localized. Example:

Namespaces

-

Unnamed namespaces in .cc files are -encouraged. With named namespaces, choose the name based on -the -project, and possibly its -path. Do not use a using-directive. -Do not use inline namespaces.

+

With few exceptions, place code in a namespace. Namespaces +should have unique names based on the project name, and possibly +its path. Unnamed namespaces in .cc files are +encouraged. Do not use using-directives. Do not use +inline namespaces.

@@ -448,16 +522,17 @@ name collisions in the global scope.

-

Namespaces provide a (hierarchical) axis of naming, in -addition to the (also hierarchical) name axis provided by -classes.

+

Namespaces provide a method for preventing name conflicts +in large programs while allowing most code to use reasonably +short names.

For example, if two different projects have a class Foo in the global scope, these symbols may collide at compile time or at runtime. If each project -places their code in a namespace, -project1::Foo and project2::Foo -are now distinct symbols that do not collide.

+places their code in a namespace, project1::Foo +and project2::Foo are now distinct symbols that +do not collide, and code within each project's namespace +can continue to refer to Foo without the prefix.

Inline namespaces automatically place their names in the enclosing scope. Consider the following snippet, for @@ -478,10 +553,9 @@ across versions.

-

Namespaces can be confusing, because they provide an -additional (hierarchical) axis of naming, in addition to -the (also hierarchical) name axis provided by -classes.

+

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 @@ -491,13 +565,18 @@ some larger versioning policy.

Use of unnamed namespaces in header files can easily cause violations of the C++ One Definition Rule (ODR).

+ +

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

Use namespaces according to the policy described below. Terminate namespaces with comments as shown in the -given examples.

+given examples. See also the rules on +Namespace Names.

Unnamed Namespaces

@@ -521,12 +600,6 @@ bool UpdateInternals(Frobber* f, int newval) { } // 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.

  • Do not use unnamed namespaces in .h @@ -539,11 +612,12 @@ bool UpdateInternals(Frobber* f, int newval) {
    • +

      Namespaces wrap the entire source file after includes, - gflags definitions/declarations, and - forward declarations of classes from other namespaces:

      + gflags definitions/declarations + and forward declarations of classes from other namespaces.

      // In the .h file
       namespace mynamespace {
      @@ -570,30 +644,27 @@ void MyClass::Foo() {
       }  // namespace mynamespace
       
      -

      The typical .cc file might have more - complex detail, including the need to reference - classes in other namespaces.

      - +

      More complex .cc files might have additional details, + like flags or using-declarations.

      #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.
      +using ::foo::bar;
       
      -namespace b {
      +namespace a {
       
      -...code for b...         // Code goes against the left margin.
      +...code for a...         // Code goes against the left margin.
       
      -}  // namespace b
      +}  // namespace a
       
    • Do not declare anything in namespace - std, not even forward declarations of + std, 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 @@ -608,118 +679,59 @@ using namespace foo;
    • You may use a using-declaration - anywhere in a .cc file, and in functions, - methods or classes in .h files.

      + anywhere in a .cc file (including in + the global namespace), and in functions, + methods, classes, or within internal namespaces in + .h files.

      + +

      Do not use using-declarations in .h + files except in explicitly marked internal-only + namespaces, because anything imported into a namespace + in a .h file becomes part of the public + API exported by that file.

      // OK in .cc files.
      -// Must be in a function, method or class in .h files.
      +// Must be in a function, method, internal namespace, 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.

      +
    • Namespace aliases are allowed anywhere where + a using-declaration is allowed. In particular, + namespace aliases should not be used at namespace scope + in .h files except in explicitly marked + internal-only namespaces.

      // Shorten access to some commonly used names in .cc files.
      -namespace fbz = ::foo::bar::baz;
      +namespace baz = ::foo::bar::baz;
      +
      -// Shorten access to some commonly used names (in a .h file). +
      // 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;
      +namespace impl {  // Internal, not part of the API.
      +namespace sidetable = ::pipeline_diagnostics::sidetable;
      +}  // namespace impl
       
       inline void my_inline_function() {
         // namespace alias local to a function (or method).
      -  namespace fbz = ::foo::bar::baz;
      +  namespace baz = ::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.

      -
    • - -
    • Do not use inline namespaces.
    • +
    • Do not use inline namespaces.
    - - - - - -
  • - -

    Nested Classes

    - -
    -

    Although you may use public nested classes when they are -part of an interface, consider a namespace -to keep declarations out of the global scope.

    -
    - -
    - -
    -

    A class can define another class within it; this is also -called a member class.

    - - -
    class Foo {
    -
    - private:
    -  // Bar is a member class, nested within Foo.
    -  class Bar {
    -    ...
    -  };
    -
    -};
    -
    -
    - -
    -

    This is useful when the nested (or member) class is only -used by the enclosing class; making it a member puts it -in the enclosing class scope rather than polluting the -outer scope with the class name. Nested classes can be -forward declared within the enclosing class and then -defined in the .cc file to avoid including -the nested class definition in the enclosing class -declaration, since the nested class definition is usually -only relevant to the implementation.

    -
    - -
    -

    Nested classes can be forward-declared only within the -definition of the enclosing class. Thus, any header file -manipulating a Foo::Bar* pointer will have -to include the full class declaration for -Foo.

    -
    - -
    -

    Do not make nested classes public unless they are -actually part of the interface, e.g., a class that holds a -set of options for some method.

    -
    - -
    -

    Nonmember, Static Member, and Global Functions

    -

    Prefer nonmember functions within a namespace or static -member functions to global functions; use completely global -functions rarely.

    +

    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.

    @@ -744,15 +756,24 @@ Nonmember functions should not depend on external variables, and should nearly always exist in a namespace. Rather than creating classes only to group static member functions which do not share static data, use -namespaces instead.

    - -

    Functions defined in the same compilation unit as -production classes may introduce unnecessary coupling and -link-time dependencies when directly called from other -compilation units; static member functions are -particularly susceptible to this. Consider extracting a -new class, or placing the functions in a namespace -possibly in a separate library.

    +namespaces instead. For a header +myproject/foo_bar.h, for example, write

    +
    namespace myproject {
    +namespace foo_bar {
    +void Function1();
    +void Function2();
    +}
    +}
    +
    +

    instead of

    +
    namespace myproject {
    +class FooBar {
    + public:
    +  static void Function1();
    +  static void Function2();
    +};
    +}
    +

    If you must define a nonmember function and it is only needed in its .cc file, use an unnamed @@ -829,11 +850,11 @@ for (int i = 0; i < 1000000; ++i) {

    Static and Global Variables

    -

    Static or global variables of class type are forbidden: -they cause hard-to-find bugs due to indeterminate order of -construction and destruction. However, such variables are -allowed if they are constexpr: they have no -dynamic initialization or destruction.

    +

    Variables of class type with + static storage duration are forbidden: they cause hard-to-find bugs due + to indeterminate order of construction and destruction. However, such + variables are allowed if they are constexpr: they have no + dynamic initialization or destruction.

    @@ -916,200 +937,175 @@ don'ts you should follow when writing a class.

    Doing Work in Constructors

    -

    Avoid doing complex initialization in constructors (in -particular, initialization that can fail or that requires -virtual method calls).

    +

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

    -

    It is possible to perform initialization in the body +

    It is possible to perform arbitrary initialization in the body of the constructor.

    -

    Convenience in typing. No need to worry about whether the -class has been initialized or not.

    +
      +
    • No need to worry about whether the class has been initialized or + not.
    • + +
    • Objects that are fully initialized by constructor call can + be const and may also be easier to use with standard containers + or algorithms.
    • +
    +

    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.
    • +
    • There is no easy way for constructors to signal errors, short of + crashing the program (not always appropriate) or using exceptions + (which are forbidden).
    • + +
    • If the work fails, we now have an object whose initialization + code failed, so it may be an unusual state requiring a bool + IsValid() state checking mechanism (or similar) which is easy + to forget to call.
    • + +
    • You cannot take address of a constructor, so whatever work is done in + the constructor cannot easily be handed off to, for example, another + thread.
    -

    Constructors should never call virtual functions or -attempt to raise non-fatal failures. If your object requires -non-trivial initialization, consider using - a factory function or Init() -method.

    +

    Constructors should never call virtual functions. If appropriate +for your code +, +terminating the program may be an appropriate error handling +response. Otherwise, consider a factory function +or Init() method. Avoid Init() methods on objects with +no other states that affect which public methods may be called +(semi-constructed objects of this form are particularly hard to work +with correctly).

    -

    Initialization

    + +

    Implicit Conversions

    -

    If your class defines member variables, you must provide an -in-class initializer for every member variable or write a -constructor (which can be a default constructor). If you do -not declare any constructors yourself then the compiler -will generate a default constructor for you, which may -leave some fields uninitialized or initialized to -inappropriate values.

    +

    Do not define implicit conversions. Use the explicit +keyword for conversion operators and single-argument +constructors.

    -

    The default constructor is called when we -new a class object with no arguments. It is always -called when calling new[] (for arrays). In-class -member initialization means declaring a member variable using a -construction like int count_ = 17; or -string name_{"abc"};, as opposed to just -int count_; or string name_;.

    -
    +

    Implicit conversions allow an +object of one type (called the source type) to +be used where a different type (called the destination +type) is expected, such as when passing an +int argument to a function that takes a +double parameter.

    -
    -

    A user-defined default constructor is used to -initialize an object if no initializer is provided. It -can ensure that an object is always in a valid and usable -state as soon as it's constructed; it can also ensure -that an object is initially created in an obviously -"impossible" state, to aid debugging.

    +

    In addition to the implicit conversions defined by the language, +users can define their own, by adding appropriate members to the +class definition of the source or destination type. An implicit +conversion in the source type is defined by a type conversion operator +named after the destination type (e.g. operator +bool()). An implicit conversion in the destination +type is defined by a converting constructor, which +is a constructor that can take the source type as its only +argument. Note that a multi-parameter constructor can still +be a converting constructor, if all but the first parameter +have default values.

    -

    In-class member initialization ensures that a member -variable will be initialized appropriately without having -to duplicate the initialization code in multiple -constructors. This can reduce bugs where you add a new -member variable, initialize it in one constructor, and -forget to put that initialization code in another -constructor.

    -
    +

    The explicit keyword can be applied to a constructor +or (since C++11) a conversion operator, to ensure that it can only be +used when the destination type is explicit at the point of use, +e.g. with a cast. This applies not only to implicit conversions, but to +C++11's list initialization syntax:

    +
    class Foo {
    +  explicit Foo(int x, double y);
    +  ...
    +};
     
    -
    -

    Explicitly defining a default constructor is extra -work for you, the code writer.

    - -

    In-class member initialization is potentially -confusing if a member variable is initialized as part of -its declaration and also initialized in a constructor, -since the value in the constructor will override the -value in the declaration.

    -
    - -
    -

    Use in-class member initialization for simple -initializations, especially when a member variable must -be initialized the same way in more than one -constructor.

    - -

    If your class defines member variables that aren't -initialized in-class, and if it has no other -constructors, you must define a default constructor (one -that takes no arguments). It should preferably initialize -the object in such a way that its internal state is -consistent and valid.

    - -

    The reason for this is that if you have no other -constructors and do not define a default constructor, the -compiler will generate one for you. This compiler -generated constructor may not initialize your object -sensibly.

    - -

    If your class inherits from an existing class but you -add no new member variables, you are not required to have -a default constructor.

    -
    - -
    - -

    Explicit Constructors

    - -
    -

    Use the C++ keyword explicit for constructors -callable with one argument.

    -
    - -
    - -
    -

    Normally, if a -constructor can be called with one argument, it can be used as a -conversion. For instance, if you define -Foo::Foo(string name) and then pass a string -to a function that expects a Foo, the -constructor will be called to convert the string into a -Foo and will pass the Foo to -your function for you. This can be convenient but is also -a source of trouble when things get converted and new -objects created without you meaning them to. Declaring a -constructor explicit prevents it from being -invoked implicitly as a conversion.

    -

    In addition to single-parameter constructors, this also -applies to constructors where every parameter after the -first has a default value, e.g., -Foo::Foo(string name, int id = 42).

    -
    - -
    -

    Avoids undesirable conversions.

    -
    - -
    -

    None.

    -
    - -
    - -

    We require all constructors that are callable with -a single argument to be -explicit. Always put explicit in front of -such constructors in the class definition: -explicit Foo(string name);

    - -

    Copy and move constructors are exceptions: they should not be -explicit. Classes that are intended to be transparent -wrappers around other classes are also exceptions. -Such exceptions should be clearly marked with -comments.

    - -

    Finally, constructors that take only a -std::initializer_list may be non-explicit. This permits -construction of your type from a braced initializer list, as in an assignment-style initialization, -function argument, or return statement. For example:

    -
      MyType m = {1, 2};
    -  MyType MakeMyType() { return {1, 2}; }
    -  TakeMyType({1, 2});
    +void Func(Foo f);
     
    +
    Func({42, 3.14});  // Error
    +
    +This kind of code isn't technically an implicit conversion, but the +language treats it as one as far as explicit is concerned. +
    + +
    +
      +
    • Implicit conversions can make a type more usable and + expressive by eliminating the need to explicitly name a type + when it's obvious.
    • +
    • Implicit conversions can be a simpler alternative to + overloading.
    • +
    • List initialization syntax is a concise and expressive + way of initializing objects.
    • +
    +
    + +
    +
      +
    • Implicit conversions can hide type-mismatch bugs, where the + destination type does not match the user's expectation, or + the user is unaware that any conversion will take place.
    • + +
    • Implicit conversions can make code harder to read, particularly + in the presence of overloading, by making it less obvious what + code is actually getting called.
    • + +
    • Constructors that take a single argument may accidentally + be usable as implicit type conversions, even if they are not + intended to do so.
    • + +
    • When a single-argument constructor is not marked + explicit, there's no reliable way to tell whether + it's intended to define an implicit conversion, or the author + simply forgot to mark it.
    • + +
    • It's not always clear which type should provide the conversion, + and if they both do, the code becomes ambiguous.
    • + +
    • List initialization can suffer from the same problems if + the destination type is implicit, particularly if the + list has only a single element.
    • +
    +
    + +
    +

    Type conversion operators, and constructors that are +callable with a single argument, must be marked +explicit in the class definition. As an +exception, copy and move constructors should not be +explicit, since they do not perform type +conversion. Implicit conversions can sometimes be necessary and +appropriate for types that are designed to transparently wrap other +types. In that case, contact +your project leads to request +a waiver of this rule.

    + +

    Constructors that cannot be called with a single argument +should usually omit explicit. Constructors that +take a single std::initializer_list parameter should +also omit explicit, in order to support copy-initialization +(e.g. MyType m = {1, 2};).

    @@ -1191,24 +1187,44 @@ copying, which can cause performance problems.

    -

    Make your type copyable/movable if it will be useful, and if it -makes sense in the context of the rest of the API. -As a rule of thumb, if the behavior (including computational -complexity) of a copy isn't immediately obvious to users of your type, -your type shouldn't be copyable. If you choose to make it copyable, -define both copy operations (constructor and assignment). If your -type is copyable and a move operation is more efficient than a copy, -define both move operations (constructor and assignment). -If your type is not copyable, but the correctness of a move is obvious -to users of the type and its fields support it, you may make the type -move-only by defining both of the move operations. +

    Make your type copyable/movable if it will be useful, and if it makes sense +in the context of the rest of the API. As a rule of thumb, if the behavior +(including computational complexity) of a copy isn't immediately obvious to +users of your type, your type shouldn't be copyable. If you define a copy or +move constructor, define the corresponding assignment operator, and vice-versa. +If your type is copyable, do not define move operations unless they are +significantly more efficient than the corresponding copy operations. If your +type is not copyable, but the correctness of a move is obvious to users of the +type, you may make the type move-only by defining both of the move operations.

    -

    Prefer to define copy and move operations with = default. -Defining non-default move operations currently requires a style -exception. Remember to review the correctness of any defaulted -operations as you would any other code. -

    +

    If your type provides copy operations, it is recommended that you design +your class so that the default implementation of those operations is correct +and that you explicitly define them with = default. Remember to +review the correctness of any defaulted operations as you would any other +code.

    + +
    class Foo {  // Copyable and movable type.
    + public:
    +  Foo(Foo&& other) = default;
    +  Foo(const Foo& other) = default;
    +  Foo& operator=(Foo&& other) = default;
    +  Foo& operator=(const Foo& other) = default;
    +
    + private:
    +  string field_;
    +};
    +
    + +
    class Foo {
    + public:
    +  Foo(Foo&& other) : field_(other.field) {}
    +  // Bad, defines only move constructor, but not operator=.
    +
    + private:
    +  Field field_;
    +};
    +

    Due to the risk of slicing, avoid providing an assignment operator or public copy/move constructor for a class that's @@ -1249,7 +1265,7 @@ syntax. For example:

    ... } -X::X() : X("") { } +X::X() : X("") {}

    Inheriting constructors allow a derived class to have @@ -1547,95 +1563,134 @@ to end with Interface.

    Operator Overloading

    -

    Do not overload operators except in rare, special -circumstances. Do not create user-defined literals.

    +

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

    -

    A class can -define that operators such as + and -/ operate on the class as if it were a -built-in type. An overload of operator"" -allows the built-in literal syntax to be used to create -objects of class types.

    +

    C++ permits user code to +declare +overloaded versions of the built-in operators using the +operator keyword, so long as one of the parameters +is a user-defined type. The operator keyword also +permits user code to define new kinds of literals using +operator"", and to define type-conversion functions +such as operator bool().

    -

    Operator overloading can make code appear more -intuitive because a class will behave in the same way as -built-in types (such as int). Overloaded -operators are more playful names for functions that are -less-colorfully named, such as Equals() or -Add().

    - -

    For some template functions to work correctly, you may -need to define operators.

    +

    Operator overloading can make code more concise and +intuitive by enabling user-defined types to behave the same +as built-in types. Overloaded operators are the idiomatic names +for certain operations (e.g. ==, <, +=, and <<), and adhering to +those conventions can make user-defined types more readable +and enable them to interoperate with libraries that expect +those names.

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

    -

    While operator overloading can make code more intuitive, -it has several drawbacks:

    -
      -
    • It can fool our intuition into thinking that - expensive operations are cheap, built-in +
    • Providing a correct, consistent, and unsurprising + set of operator overloads requires some care, and failure + to do so can lead to confusion and bugs.
    • + +
    • Overuse of operators can lead to obfuscated code, + particularly if the overloaded operator's semantics + don't follow convention.
    • + +
    • The hazards of function overloading apply just as + much to operator overloading, if not more so.
    • + +
    • Operator overloads can fool our intuition into + thinking that expensive operations are cheap, built-in operations.
    • -
    • It is much harder to find the call sites for - overloaded operators. Searching for - Equals() is much easier than searching for - relevant invocations of ==.
    • +
    • Finding the call sites for overloaded operators may + requre a search tool that's aware of C++ syntax, rather + than e.g. grep.
    • -
    • 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.
    • +
    • If you get the argument type of an overloaded operator + wrong, you may get a different overload rather than a + compiler error. For example, foo < bar + may do one thing, while &foo < &bar + does something totally different.
    • -
    • User-defined literals allow creating new syntactic - forms that are unfamiliar even to experienced C++ +
    • Certain operator overloads are inherently hazardous. + Overloading unary & can cause the same + code to have different meanings depending on whether + the overload declaration is visible. Overloads of + &&, ||, and , + (comma) cannot match the evaluation-order semantics of the + built-in operators.
    • + +
    • Operators are often defined outside the class, + so there's a risk of different files introducing + different definitions of the same operator. If both + definitions are linked into the same binary, this results + in undefined behavior, which can manifest as subtle + run-time bugs.
    • + +
    • User-defined literals allow the creation of new + syntactic forms that are unfamiliar even to experienced C++ programmers.
    - -

    Overloading also has surprising ramifications. For -instance, if a class overloads unary -operator&, it cannot safely be -forward-declared.

    -

    In general, do not overload operators. You can define -ordinary functions like Equals() if -you need them. Likewise, avoid the dangerous unary -operator& at all costs, if there's any -possibility the class might be forward-declared.

    +

    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.

    -

    Do not overload operator"", i.e. do not -introduce user-defined literals.

    +

    Define operators only on your own types. More precisely, +define them in the same headers, .cc files, and namespaces +as the types they operate on. That way, the operators are available +wherever the type is, minimizing the risk of multiple +definitions. If possible, avoid defining operators as templates, +because they must satisfy this rule for any possible template +arguments. If you define an operator, also define +any related operators that make sense, and make sure they +are defined consistently. For example, if you overload +<, overload all the comparison operators, +and make sure < and > never +return true for the same arguments.

    -

    However, there may be rare cases where you need to -overload an operator to interoperate with templates or -"standard" C++ classes (such as -operator<<(ostream&, const T&) -for logging). These are acceptable if fully justified, but you should try to avoid these -whenever possible. In particular, do not overload -operator== or operator< just -so that your class can be used as a key in an STL -container; instead, you should create equality and -comparison functor types when declaring the -container.

    +

    Prefer to define non-modifying binary operators as +non-member functions. If a binary operator is defined as a +class member, implicit conversions will apply to the +right-hand argument, but not the left-hand one. It will +confuse your users if a < b compiles but +b < a doesn't.

    -

    Some of the STL algorithms do require you to overload -operator==, and you may do so in these -cases, provided you document why.

    +

    Don't go out of your way to avoid defining operator +overloads. For example, prefer to define ==, +=, and <<, rather than +Equals(), CopyFrom(), and +PrintTo(). Conversely, don't define +operator overloads just because other libraries expect +them. For example, if your type doesn't have a natural +ordering, but you want to store it in a std::set, +use a custom comparator rather than overloading +<.

    -

    See also Copyable and Movable -Types and Function Overloading.

    +

    Do not overload &&, ||, +, (comma), or unary &. Do not overload +operator"", i.e. do not introduce user-defined +literals.

    + +

    Type conversion operators are covered in the section on +implicit conversions. +The = operator is covered in the section on +copy constructors. Overloading +<< for use with streams is covered in the +section on streams. See also the rules on +function overloading, which +apply to operator overloading as well.

    @@ -1643,31 +1698,17 @@ Types and Function Overloading.

    Access Control

    -

    Make data members private, and provide access -to them through accessor functions as needed (for technical +

    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). Typically a variable would be called -foo_ and the accessor function -foo(). You may also want a mutator function -set_foo(). Exception: static -const data members (typically called -kFoo) need not be private.

    +Test).

    -
    - -

    The definitions of accessors are usually inlined in -the header file.

    - -

    See also Inheritance and -Function Names.

    - -
    -

    Declaration Order

    @@ -1703,17 +1744,12 @@ be in the following order:

    members) -

    Friend declarations should always be in the private -section. If copying and assignment are disabled with a macro -such as DISALLOW_COPY_AND_ASSIGN, it should be +

    If copying and assignment are disabled with a macro such as +DISALLOW_COPY_AND_ASSIGN, it should be at the end of the private: section, and should be the last thing in the class. See Copyable and Movable Types.

    -

    Method definitions in the corresponding -.cc file should be the same as the -declaration order, as much as possible.

    -

    Do not put large method definitions inline in the class definition. Usually, only trivial or performance-critical, and very short, methods may be @@ -1722,6 +1758,34 @@ Functions for more details.

    +

    Functions

    + +

    Parameter Ordering

    + +
    +

    When defining a function, parameter order is: inputs, then +outputs.

    +
    + +
    +

    Parameters to C/C++ functions are either input to the +function, output from the function, or both. Input +parameters are usually values or const +references, while output and input/output parameters will +be non-const pointers. When ordering +function parameters, put all input-only parameters before +any output parameters. In particular, do not add new +parameters to the end of the function just because they +are new; place new input-only parameters before the +output parameters.

    + +

    This is not a hard-and-fast rule. Parameters that are +both input and output (often classes/structs) muddy the +waters, and, as always, consistency with related +functions may require you to bend the rule.

    + +
    +

    Write Short Functions

    @@ -1752,6 +1816,255 @@ the function into smaller and more manageable pieces.

    +

    Reference Arguments

    + +
    +

    All parameters passed by reference must be labeled +const.

    +
    + +
    + +
    +

    In C, if a +function needs to modify a variable, the parameter must +use a pointer, eg int foo(int *pval). In +C++, the function can alternatively declare a reference +parameter: int foo(int &val).

    +
    + +
    +

    Defining a parameter as reference avoids ugly code like +(*pval)++. Necessary for some applications +like copy constructors. Makes it clear, unlike with +pointers, that a null pointer is not a possible +value.

    +
    + +
    +

    References can be confusing, as they have value syntax +but pointer semantics.

    +
    + +
    +

    Within function parameter lists all references must be +const:

    + +
    void Foo(const string &in, string *out);
    +
    + +

    In fact it is a very strong convention in Google code +that input arguments are values or const +references while output arguments are pointers. Input +parameters may be const pointers, but we +never allow non-const reference parameters +except when required by convention, e.g., +swap().

    + +

    However, there are some instances where using +const T* is preferable to const +T& for input parameters. For example:

    + +
      +
    • You want to pass in a null pointer.
    • + +
    • The function saves a pointer or reference to the + input.
    • +
    + +

    Remember that most of the time input +parameters are going to be specified as const +T&. Using const T* instead +communicates to the reader that the input is somehow +treated differently. So if you choose const +T* rather than const T&, do so +for a concrete reason; otherwise it will likely confuse +readers by making them look for an explanation that +doesn't exist.

    +
    + +
    + +

    Function Overloading

    + +
    +

    Use overloaded functions (including constructors) only if a +reader looking at a call site can get a good idea of what +is happening without having to first figure out exactly +which overload is being called.

    +
    + +
    + +
    +

    You may write a function that takes a const +string& and overload it with another that +takes const char*.

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

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

    +
    + +
    +

    If a function is overloaded by the argument types alone, +a reader may have to understand C++'s complex matching +rules in order to tell what's going on. Also many people +are confused by the semantics of inheritance if a derived +class overrides only some of the variants of a +function.

    +
    + +
    +

    If you want to overload a function, consider qualifying +the name with some information about the arguments, e.g., +AppendString(), AppendInt() +rather than just Append(). If you are +overloading a function to support variable number of +arguments of the same type, consider making it take a +vector so that the user can use an +initializer list + to specify the arguments.

    +
    + +
    + +

    Default Arguments

    + +
    +

    We do not allow default function parameters, except in +limited situations as explained below. Simulate them with +function overloading instead, if appropriate.

    +
    + +
    + +
    +

    Often you have a function that uses default values, but +occasionally you want to override the defaults. Default +parameters allow an easy way to do this without having to +define many functions for the rare exceptions. Compared +to overloading the function, default arguments have a +cleaner syntax, with less boilerplate and a clearer +distinction between 'required' and 'optional' +arguments.

    +
    + +
    +

    Function pointers are confusing in the presence of +default arguments, since the function signature often +doesn't match the call signature. Adding a default +argument to an existing function changes its type, which +can cause problems with code taking its address. Adding +function overloads avoids these problems. In addition, +default parameters may result in bulkier code since they +are replicated at every call-site -- as opposed to +overloaded functions, where "the default" appears only in +the function definition.

    +
    + +
    +

    While the cons above are not that onerous, they still +outweigh the (small) benefits of default arguments over +function overloading. So except as described below, we +require all arguments to be explicitly specified.

    + +

    One specific exception is when the function is a +static function (or in an unnamed namespace) in a .cc +file. In this case, the cons don't apply since the +function's use is so localized.

    + +

    In addition, default function parameters are allowed in +constructors. Most of the cons listed above don't apply to +constructors because it's impossible to take their address.

    + +

    Another specific exception is when default arguments +are used to simulate 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);
    +
    +
    + +
    + +

    Trailing Return Type Syntax

    +
    +

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

    +
    + +
    +

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

    +
    int foo(int x);
    +
    +

    The new form, introduced in C++11, uses the auto + keyword before the function name and a trailing return type after + the argument list. For example, the declaration above could + equivalently be written:

    +
    auto foo(int x) -> int;
    +
    +

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

    +
    + +
    +
    +

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

    +

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

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

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

    +

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

    +
    + +
    +

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

    + +
    +
    +

    Google-Specific Magic

    @@ -1788,14 +2101,14 @@ 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 @@ -1935,81 +2248,11 @@ you can download

    Other C++ Features

    -

    Reference Arguments

    - -
    -

    All parameters passed by reference must be labeled -const.

    -
    - -
    - -
    -

    In C, if a -function needs to modify a variable, the parameter must -use a pointer, eg int foo(int *pval). In -C++, the function can alternatively declare a reference -parameter: int foo(int &val).

    -
    - -
    -

    Defining a parameter as reference avoids ugly code like -(*pval)++. Necessary for some applications -like copy constructors. Makes it clear, unlike with -pointers, that a null pointer is not a possible -value.

    -
    - -
    -

    References can be confusing, as they have value syntax -but pointer semantics.

    -
    - -
    -

    Within function parameter lists all references must be -const:

    - -
    void Foo(const string &in, string *out);
    -
    - -

    In fact it is a very strong convention in Google code -that input arguments are values or const -references while output arguments are pointers. Input -parameters may be const pointers, but we -never allow non-const reference parameters -except when required by convention, e.g., -swap().

    - -

    However, there are some instances where using -const T* is preferable to const -T& for input parameters. For example:

    - -
      -
    • You want to pass in a null pointer.
    • - -
    • The function saves a pointer or reference to the - input.
    • -
    - -

    Remember that most of the time input -parameters are going to be specified as const -T&. Using const T* instead -communicates to the reader that the input is somehow -treated differently. So if you choose const -T* rather than const T&, do so -for a concrete reason; otherwise it will likely confuse -readers by making them look for an explanation that -doesn't exist.

    -
    - -
    -

    Rvalue References

    -

    Use rvalue references only to define move constructors and move -assignment operators. Do not -use std::forward. +

    Use rvalue references only to define move constructors and move assignment +operators, or for perfect forwarding.

    @@ -2039,7 +2282,8 @@ rvalue reference to a string.

  • Rvalue references make it possible to write a generic function wrapper that forwards its arguments to another function, and works whether or not its - arguments are temporary objects.
  • + arguments are temporary objects. (This is sometimes called + "perfect forwarding".)
  • Rvalue references make it possible to implement types that are movable but not copyable, which can be @@ -2064,124 +2308,11 @@ rvalue reference to a string.

  • -

    Use rvalue references only to define move constructors and move -assignment operators, as described in -Copyable and Movable Types. -Do not use std::forward utility function. You may -use std::move to express moving a value from one object -to another rather than copying it.

    -
    - -
    - -

    Function Overloading

    - -
    -

    Use overloaded functions (including constructors) only if a -reader looking at a call site can get a good idea of what -is happening without having to first figure out exactly -which overload is being called.

    -
    - -
    - -
    -

    You may write a function that takes a const -string& and overload it with another that -takes const char*.

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

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

    -
    - -
    -

    If a function is overloaded by the argument types alone, -a reader may have to understand C++'s complex matching -rules in order to tell what's going on. Also many people -are confused by the semantics of inheritance if a derived -class overrides only some of the variants of a -function.

    -
    - -
    -

    If you want to overload a function, consider qualifying -the name with some information about the arguments, e.g., -AppendString(), AppendInt() -rather than just Append().

    -
    - -
    - -

    Default Arguments

    - -
    -

    We do not allow default function parameters, except in -limited situations as explained below. Simulate them with -function overloading instead, if appropriate.

    -
    - -
    - -
    -

    Often you have a function that uses default values, but -occasionally you want to override the defaults. Default -parameters allow an easy way to do this without having to -define many functions for the rare exceptions. Compared -to overloading the function, default arguments have a -cleaner syntax, with less boilerplate and a clearer -distinction between 'required' and 'optional' -arguments.

    -
    - -
    -

    Function pointers are confusing in the presence of -default arguments, since the function signature often -doesn't match the call signature. Adding a default -argument to an existing function changes its type, which -can cause problems with code taking its address. Adding -function overloads avoids these problems. In addition, -default parameters may result in bulkier code since they -are replicated at every call-site -- as opposed to -overloaded functions, where "the default" appears only in -the function definition.

    -
    - -
    -

    While the cons above are not that onerous, they still -outweigh the (small) benefits of default arguments over -function overloading. So except as described below, we -require all arguments to be explicitly specified.

    - -

    One specific exception is when the function is a -static function (or in an unnamed namespace) in a .cc -file. In this case, the cons don't apply since the -function's use is so localized.

    - -

    In addition, default function parameters are allowed in -constructors. Most of the cons listed above don't apply to -constructors because it's impossible to take their address.

    - -

    Another specific exception is when default arguments -are used to simulate 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);
    -
    +

    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.

    @@ -2214,7 +2345,7 @@ on my machine, but dies mysteriously in production".

    Use a safe allocator instead, such as -std::vector or +vector or std::unique_ptr<T[]>.

    @@ -2542,108 +2673,106 @@ RTTI section for guidance on the use of

    Streams

    -

    Use streams only for logging.

    +

    Use streams where appropriate, and stick to "simple" +usages.

    -

    Streams are a replacement for printf() -and scanf().

    +

    Streams are the standard I/O abstraction in C++, as +exemplified by the standard header <iostream>. +They are widely used in Google code, but only for debug logging +and test diagnostics.

    -

    With streams, you do not need to know the type of the -object you are printing. You do not have problems with -format strings not matching the argument list. (Though -with gcc, you do not have that problem with -printf either.) Streams have automatic -constructors and destructors that open and close the -relevant files.

    +

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

    + +

    Streams provide first-class support for console I/O +via std::cin, std::cout, +std::cerr, and std::clog. +The C APIs do as well, but are hampered by the need to +manually buffer the input.

    -

    Streams make it difficult to do functionality like -pread(). Some formatting (particularly the -common format string idiom %.*s) is -difficult if not impossible to do efficiently using -streams without using printf-like hacks. -Streams do not support operator reordering (the -%1$s directive), which is helpful for -internationalization.

    +
      +
    • Stream formatting can be configured by mutating the +state of the stream. Such mutations are persistent, so +the behavior of your code can be affected by the entire +previous history of the stream, unless you go out of your +way to restore it to a known state every time other code +might have touched it. User code can not only modify the +built-in state, it can add new state variables and behaviors +through a registration system.
    • + +
    • It is difficult to precisely control stream output, due +to the above issues, the way code and data are mixed in +streaming code, and the use of operator overloading (which +may select a different overload than you expect).
    • + +
    • The practice of building up output through chains +of << operators interferes with +internationalization, because it bakes word order into the +code, and streams' support for localization is +flawed.
    • + + + + + +
    • The streams API is subtle and complex, so programmers must +develop experience with it in order to use it effectively. +However, streams were historically banned in Google code (except +for logging and diagnostics), so Google engineers tend not to +have that experience. Consequently, streams-based code is likely +to be less readable and maintainable by Googlers than code based +on more familiar abstractions.
    • + +
    • Resolving the many overloads of << is +extremely costly for the compiler. When used pervasively in a +large code base, it can consume as much as 20% of the parsing +and semantic analysis time.
    • +
    +

    Use streams only when they are the best tool for the job. +This is typically the case when the I/O is ad-hoc, local, +human-readable, and targeted at other developers rather than +end-users. Be consistent with the code around you, and with the +codebase as a whole; if there's an established tool for +your problem, use that tool instead.

    +

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

    -

    Do not use streams, except where -required by a logging interface. Use -printf-like routines instead.

    +

    If you do use streams, avoid the stateful parts of the +streams API (other than error state), such as imbue(), +xalloc(), and register_callback(). +Use explicit formatting functions rather than +stream manipulators or formatting flags to control formatting +details such as number base, precision, or padding.

    -

    There are various pros and cons to using streams, but -in this case, as in many other cases, consistency trumps -the debate. Do not use streams in your code.

    -
    - -
    -

    Extended Discussion

    - -

    There has been debate on this issue, so this explains -the reasoning in greater depth. Recall the Only One Way -guiding principle: we want to make sure that whenever we -do a certain type of I/O, the code looks the same in all -those places. Because of this, we do not want to allow -users to decide between using streams or using -printf plus Read/Write/etc. Instead, we -should settle on one or the other. We made an exception -for logging because it is a pretty specialized -application, and for historical reasons.

    - -

    Proponents of streams have argued that streams are the -obvious choice of the two, but the issue is not actually -so clear. For every advantage of streams they point out, -there is an equivalent disadvantage. The biggest -advantage is that you do not need to know the type of the -object to be printing. This is a fair point. But, there -is a downside: you can easily use the wrong type, and the -compiler will not warn you. It is easy to make this kind -of mistake without knowing when using streams.

    - -
    cout << this;  // Prints the address
    -cout << *this;  // Prints the contents
    -
    - -

    The compiler does not generate an error because -<< has been overloaded. We discourage -overloading for just this reason.

    - -

    Some say printf formatting is ugly and -hard to read, but streams are often no better. Consider -the following two fragments, both with the same typo. -Which is easier to discover?

    - - -
    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 -right wrappers," but if it is true for one scheme, is it -not also true for the other? Also, remember the goal is -to make the language smaller, not add yet more machinery -that someone has to learn.)

    - -

    Either path would yield different advantages and -disadvantages, and there is not a clearly superior -solution. The simplicity doctrine mandates we settle on -one of them though, and the majority decision was on -printf + -read/write.

    +

    Overload << as a streaming operator +for your type only if your type represents a value, and +<< writes out a human-readable string +representation of that value. Avoid exposing implementation +details in the output of <<; if you need to print +object internals for debugging, use named functions instead +(a method named DebugString() is the most common +convention).

    @@ -2968,8 +3097,9 @@ problems of printing, comparisons, and structure alignment.

    systems. C99 defines some portable format specifiers. Unfortunately, MSVC 7.1 does not understand some of these specifiers and the standard is missing a few, - so we have to define our own ugly versions in some - cases (in the style of the standard include file + so we + have to define our own ugly versions in some cases + (in the style of the standard include file inttypes.h):

    @@ -2983,7 +3113,7 @@ problems of printing, comparisons, and structure alignment.

    // 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); +// printf("%" PRIuS "\n", size); #define PRIdS __PRIS_PREFIX "d" #define PRIxS __PRIS_PREFIX "x" @@ -3013,7 +3143,7 @@ problems of printing, comparisons, and structure alignment.

    int64_t %qd, %lld - %"PRId64" + %" PRId64 " @@ -3023,8 +3153,8 @@ problems of printing, comparisons, and structure alignment.

    uint64_t %qu, %llu, %llx - %"PRIu64", - %"PRIx64" + %" PRIu64 ", + %" PRIx64 " @@ -3033,7 +3163,7 @@ problems of printing, comparisons, and structure alignment.

    size_t %u - %"PRIuS", %"PRIxS" + %" PRIuS ", %" PRIxS " C99 specifies %zu @@ -3041,7 +3171,7 @@ problems of printing, comparisons, and structure alignment.

    ptrdiff_t %d - %"PRIdS" + %" PRIdS " C99 specifies %td @@ -3053,11 +3183,13 @@ problems of printing, comparisons, and structure alignment.

    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 + macro into the format, rather than the name. Note also + that spaces are required around the macro identifier to + separate it from the string literal. It is still possible, as usual, to include length specifiers, etc., after the % when using the PRI* macros. So, e.g. - printf("x = %30"PRIuS"\n", x) would + printf("x = %30" PRIuS "\n", x) would expand on 32-bit Linux to printf("x = %30" "u" "\n", x), which the compiler will treat as printf("x = %30u\n", x).

    @@ -3094,11 +3226,6 @@ problems of printing, comparisons, and structure alignment.

    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.)
  • @@ -3230,7 +3357,7 @@ memset(&data, 0, sizeof(data));

    Use auto to avoid type names that are just clutter. Continue to use manifest type declarations when it helps readability, and never use auto for -anything but local variables.

    +anything but local variables.

    @@ -3249,6 +3376,12 @@ const auto& s2 = v[0]; // s2 is a reference to v[0].
    +

    The auto keyword is also used in an +unrelated C++11 feature: it's part of the syntax for a +new kind of function declaration with a +trailing return type.

    + +

    C++ type names can sometimes be long and cumbersome, especially when they involve templates or namespaces. In @@ -3296,11 +3429,13 @@ if x was declared hundreds of lines earlier.

    they'll get copies when they didn't mean to.

    The interaction between auto and C++11 -brace-initialization can be confusing. The -declarations:

    +brace-initialization can be confusing. The exact +rules have been in flux, and compilers don't all +implement the final rules yet. +The declarations:

    -
    auto x(3);  // Note: parentheses.
    -auto y{3};  // Note: curly braces.
    +
    auto x{3};
    +auto y = {3};
     

    mean different things — @@ -3323,13 +3458,7 @@ only. Do not use auto for file-scope or namespace-scope variables, or for class members. Never initialize an auto-typed variable with a braced initializer list. - -

    The auto keyword is also used in an -unrelated C++11 feature: it's part of the syntax for a -new kind of function declaration with a trailing return -type. Trailing return types are permitted only in lambda -expressions.

    -
    +

    @@ -3431,8 +3560,9 @@ means can be confusing.

    Lambda expressions

    -

    Use lambda expressions where appropriate. Do not use -default lambda captures; write all captures explicitly.

    +

    Use lambda expressions where appropriate. Avoid +default lambda captures when capturing this or +if the lambda will escape the current scope.

    @@ -3448,6 +3578,22 @@ functions as arguments. For example:

    }); +They further allow capturing variables from the enclosing scope either +explicitly by name, or implicitly using a default capture. Default captures +implicitly capture any variable referenced in the lambda body, including +this if any members are used. The default capture must come +first and be one of & for capture by reference or += for capture by value, followed by any explicit captures which +differ from the default: + +
    int weight = 3;
    +int sum = 0;
    +// Captures `weight` (implicitly) by value and `sum` by reference.
    +std::for_each(v.begin(), v.end(), [=, &sum](int x) {
    +  sum += weight * x;
    +});
    +
    +

    Lambdas were introduced in C++11 along with a set of utilities for working with function objects, such as the polymorphic wrapper std::function. @@ -3461,6 +3607,10 @@ wrapper std::function. algorithms, which can be a readability improvement. +

  • Appropriate use of default captures can remove + redundancy and highlight important exceptions from + the default.
  • +
  • Lambdas, std::function, and std::bind can be used in combination as a general purpose callback mechanism; they make it easy @@ -3471,8 +3621,13 @@ wrapper std::function.
      +
    • Default captures make it easy to overlook an + implicit capture and use of this. +
    • +
    • Variable capture in lambdas can be tricky, and - might be a new source of dangling-pointer bugs.
    • + might be a new source of dangling-pointer bugs, + particularly if a lambda escapes the current scope.
    • It's possible for use of lambdas to get out of hand; very long nested anonymous functions can make @@ -3486,11 +3641,31 @@ wrapper std::function.
      • Use lambda expressions where appropriate, with formatting as described below.
      • -
      • Do not use default captures; write all lambda captures explicitly. -For example, instead of [=](int x) { return x + n; } -you should write [n](int x) { return x + n; } so that -readers can see immediately that n is being captured -(by value).
      • +
      • Use default captures judiciously, when it aids readability. +In particular, prefer to write lambda captures explicitly when +capturing this or if the lambda will escape the +current scope. For example, instead of: +
        {
        +  Foo foo;
        +  ...
        +  executor->Schedule([&] { Frobnicate(foo); })
        +  ...
        +}
        +// BAD! `Frobnicate` may be a member function and `foo` may be destroyed
        +// by the time the lambda runs.
        +
        +prefer to write: +
        {
        +  Foo foo;
        +  ...
        +  executor->Schedule([&foo] { Frobnicate(foo); })
        +  ...
        +}
        +// GOOD - The lambda cannot accidentally capture `this` and
        +// the explicit by-reference capture is more obvious and therefore
        +// more likely to be checked for correctness.
        +
        +
      • Keep unnamed lambdas short. If a lambda body is more than maybe five lines long, prefer to give the lambda a name, or to use a named function instead of a lambda.
      • @@ -3592,7 +3767,7 @@ collection.

        The - + Boost library collection is a popular collection of peer-reviewed, free, open-source C++ libraries.

        @@ -3622,30 +3797,27 @@ Currently, the following libraries are permitted:

        We are actively considering adding other Boost @@ -3682,14 +3857,14 @@ is discouraged because they've been superseded by standard libraries in C++11:

    @@ -3698,20 +3873,101 @@ standard libraries in C++11:

    -

    C++11

    +

    std::hash

    -

    Use libraries and language extensions from C++11 (formerly -known as C++0x) when appropriate. -Consider portability to other environments -before using C++11 features in your -project.

    +

    Do not define specializations of std::hash.

    + +
    +

    std::hash is easy to use, and simplifies the code +since you don't have to name it explicitly. Specializing +std::hash is the standard way of specifying how to +hash a type, so it's what outside resources will teach, and what +new engineers will expect.

    +
    + +
    +

    std::hash is hard to specialize. It requires a lot +of boilerplate code, and more importantly, it combines responsibility +for identifying the hash inputs with responsibility for executing the +hashing algorithm itself. The type author has to be responsible for +the former, but the latter requires expertise that a type author +usually doesn't have, and shouldn't need. The stakes here are high +because low-quality hash functions can be security vulnerabilities, +due to the emergence of + +hash flooding attacks.

    + +

    Even for experts, std::hash specializations are +inordinately difficult to implement correctly for compound types, +because the implementation cannot recursively call std::hash +on data members. High-quality hash algorithms maintain large +amounts of internal state, and reducing that state to the +size_t bytes that std::hash +returns is usually the slowest part of the computation, so it +should not be done more than once.

    + +

    Due to exactly that issue, std::hash does not work +with std::pair or std::tuple, and the +language does not allow us to extend it to support them.

    +
    + +
    +

    You can use std::hash with the types that it supports +"out of the box", but do not specialize it to support additional types. +If you need a hash table with a key type that std::hash +does not support, consider using legacy hash containers (e.g. +hash_map) for now; they use a different default hasher, +which is unaffected by this prohibition.

    + +

    If you want to use the standard hash containers anyway, you will +need to specify a custom hasher for the key type, e.g.

    +
    std::unordered_map<MyKeyType, Value, MyKeyTypeHasher> my_map;
    +

    +Consult with the type's owners to see if there is an existing hasher +that you can use; otherwise work with them to provide one, + or roll your own.

    + +

    We are planning to provide a hash function that can work with any type, +using a new customization mechanism that doesn't have the drawbacks of +std::hash.

    +
    + +
    + +

    C++11

    + +
    +

    Use libraries and language extensions from C++11 when appropriate. +Consider portability to other environments +before using C++11 features in your +project.

    + +
    + +
    + +
    +

    C++11 contains significant changes both to the language and libraries.

    @@ -3753,15 +4009,6 @@ In addition to what's described in the rest of the style guide, the following C++11 features may not be used:

      -
    • Functions (other than lambda functions) - with trailing return types, e.g. writing - auto foo() -> int; instead of int - foo();, because of a desire to preserve - stylistic consistency with the many existing function - declarations.
    • - - - @@ -3779,10 +4026,7 @@ guide, the following C++11 features may not be used:

      <fenv.h> headers, because many compilers do not support those features reliably. - - -
    • Default lambda captures.
    • -
    +
  • @@ -3806,8 +4050,7 @@ the rules are the rules.

    General Naming Rules

    -

    Function names, variable names, and filenames should be -descriptive; eschew abbreviation.

    +

    Names should be descriptive; eschew abbreviation.

    @@ -3888,8 +4131,8 @@ letter for each new word, with no underscores:

    The names of all types — classes, structs, typedefs, -and enums — have the same naming convention. Type names -should start with a capital letter and have a capital letter +enums, and type template parameters — have the same naming convention. +Type names should start with a capital letter and have a capital letter for each new word. No underscores. For example:

    // classes and structs
    @@ -3975,93 +4218,94 @@ variables.

    Constant Names

    -

    Use a k followed by mixed case, e.g., -kDaysInAWeek, for constants defined globally or within a class.

    +

    Variables declared constexpr or const, and whose value is fixed for + the duration of the program, are named with a leading "k" followed + by mixed case. For example:

    -
    - -

    As a convenience to the reader, compile-time constants of global or class scope -follow a different naming convention from other variables. -Use a k followed by words with uppercase first letters:

    -
    const int kDaysInAWeek = 7;
     
    -

    This convention may optionally be used for compile-time constants of local scope; -otherwise the usual variable naming rules apply. +

    + +

    All such variables with static storage duration (i.e. statics and globals, + see + Storage Duration for details) should be named this way. This + convention is optional for variables of other storage classes, e.g. automatic + variables, otherwise the usual variable naming rules apply.

    Function Names

    -

    Regular functions have mixed case; accessors and mutators -match the name of the variable: -MyExcitingFunction(), -MyExcitingMethod(), -my_exciting_member_variable(), -set_my_exciting_member_variable().

    +

    Regular functions have mixed case; "cheap" functions may +use lower case with underscores.

    -

    Regular Functions

    +

    Ordinarily, functions should start with a capital letter and have +a capital letter for each new word (a.k.a. "upper camel case" or "Pascal case"). +Such names should not have underscores. Prefer to capitalize acronyms as +single words (i.e. StartRpc(), not StartRPC()).

    -

    Functions should start with a capital letter and have -a capital letter for each new word. No underscores.

    - -

    If your function crashes upon an error, you should -append OrDie to the function name. This only applies to -functions which could be used by production code and to -errors that are reasonably likely to occur during normal -operation.

    - -
    AddTableEntry()
    +
    AddTableEntry()
     DeleteUrl()
     OpenFileOrDie()
     
    -

    Accessors and Mutators

    - -

    Accessors and mutators (get and set functions) should -match the name of the variable they are getting and -setting. This shows an excerpt of a class whose instance -variable is num_entries_.

    +

    Functions that are very cheap to call may instead follow the style +for variable names (all lower-case, with underscores between words). +The rule of thumb is that such a function should be so cheap that you +normally wouldn't bother caching its return value when calling it in +a loop. A canonical example is an inline method that just returns one +of the class's member variables.

    class MyClass {
      public:
       ...
    -  int num_entries() const { return num_entries_; }
    -  void set_num_entries(int num_entries) { num_entries_ = num_entries; }
    +  bool is_empty() const { return num_entries_ == 0; }
     
      private:
       int num_entries_;
     };
     
    - -

    You may also use lowercase letters for other very -short inlined functions. For example if a function were -so cheap you would not cache the value if you were -calling it in a loop, then lowercase naming would be -acceptable.

    -

    Namespace Names

    - - -

    Namespace names are all lower-case, -and based on project names and possibly their directory -structure: google_awesome_project.

    +Namespace names are all lower-case. Top-level +namespace names are based on the project name +.
    +

    The name of a top-level namespace should usually be the +name of the project or team whose code is contained in that +namespace. The code in that namespace should usually be in +a directory whose basename matches the namespace name (or +subdirectories thereof).

    -

    See Namespaces for a -discussion of namespaces and how to name them.

    + + + + +

    Keep in mind that the rule +against abbreviated names applies to namespaces just as much +as variable names. Code inside the namespace seldom needs to +mention the namespace name, so there's usually no particular need +for abbreviation anyway.

    + +

    Naming conventions for nested namespaces are at the discretion +of the team owning the enclosing namespace. If a nested namespace +is used to group related functions in a single header file, consider basing +its name on the header name, e.g. namespace foo::bar +for functions defined in the header file bar.h. +If the nested namespace is being used to distinguish implementation +details from user-facing declarations, one common choice is +internal.

    @@ -4217,24 +4461,23 @@ author line, consider deleting the author line.

    File Contents

    Every file should have a comment at the top describing -its contents.

    +its contents, unless the specific conditions described below apply.

    -

    Generally a .h file will describe the -classes that are declared in the file with an overview of -what they are for and how they are used. A -.cc file should contain more information -about implementation details or discussions of tricky -algorithms. If you feel the implementation details or a -discussion of the algorithms would 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.

    +

    A file-level comment in a .h should broadly describe +the contents of the file. If the file declares multiple abstractions, the +file-level comment should document how they are related. A 1 or 2 sentence +file-level comment may be sufficient. The detailed documentation about +individual abstractions belongs with those abstractions, not at the file +level.

    -

    Do not duplicate comments in both the .h -and the .cc. Duplicated comments -diverge.

    +

    Do not duplicate comments in both the .h and the +.cc. Duplicated comments diverge.

    -
    +

    A file-level comment may be omitted if the file declares, implements, or +tests exactly one abstraction that is documented by a comment at the point +of declaration.

    + +

    Class Comments

    @@ -4245,7 +4488,8 @@ that describes what it is for and how it should be used.

    -
    // Iterates over the contents of a GargantuanTable.  Sample usage:
    +
    // Iterates over the contents of a GargantuanTable.
    +// Example:
     //    GargantuanTableIterator* iter = table->NewIterator();
     //    for (iter->Seek("foo"); !iter->done(); iter->Next()) {
     //      process(iter->key(), iter->value());
    @@ -4256,17 +4500,15 @@ class GargantuanTableIterator {
     };
     
    -

    If you have already described a class in detail in the -comments at the top of your file feel free to simply -state "See comment at top of file for a complete -description", but be sure to have some sort of -comment.

    +

    The class comment should provide the reader with enough information to know +how and when to use the class, as well as any additional considerations +necessary to correctly use the class. Document the synchronization assumptions +the class makes, if any. If an instance of the class can be accessed by +multiple threads, take extra care to document the rules and invariants +surrounding multithreaded use.

    -

    Document the synchronization assumptions the class -makes, if any. If an instance of the class can be -accessed by multiple threads, take extra care to document -the rules and invariants surrounding multithreaded -use.

    +

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

    @@ -4343,6 +4585,12 @@ implied.

    bool IsTableFull(); +

    When documenting function overrides, focus on the +specifics of the override itself, rather than repeating +the comment from the overriden function. In many of these +cases, the override needs no additional documentation and +thus no comment is required.

    +

    When commenting constructors and destructors, remember that the person reading your code knows what constructors and destructors are for, so comments that just say @@ -4468,49 +4716,84 @@ vector<string> list{// Comments in braced lists describe the next element DoSomething(); /* For trailing block comments, one space is fine. */ -

    nullptr/NULL, true/false, 1, 2, 3...

    +

    Function Argument Comments

    -

    When you pass in a null pointer, boolean, or literal -integer values to functions, you should consider adding a -comment about what they are, or make your code -self-documenting by using constants. For example, -compare:

    +

    When the meaning of a function argument is nonobvious, consider +one of the following remedies:

    -
    bool success = CalculateSomething(interesting_value,
    -                                  10,
    -                                  false,
    -                                  NULL);  // What are these arguments??
    +
      +
    • If the argument is a literal constant, and the same constant is + used in multiple function calls in a way that tacitly assumes they're + the same, you should use a named constant to make that constraint + explicit, and to guarantee that it holds.
    • + +
    • Consider changing the function signature to replace a bool + argument with an enum argument. This will make the argument + values self-describing.
    • + +
    • For functions that have several configuration options, consider + defining a single class or struct to hold all the options + , + and pass an instance of that. + This approach has several advantages. Options are referenced by name + at the call site, which clarifies their meaning. It also reduces + function argument count, which makes function calls easier to read and + write. As an added benefit, you don't have to change call sites when + you add another option. +
    • + +
    • Replace large or complex nested expressions with named variables.
    • + +
    • As a last resort, use comments to clarify argument meanings at the + call site.
    • +
    + +Consider the following example: + +
    // What are these arguments?
    +const DecimalNumber product = CalculateProduct(values, 7, false, nullptr);
     

    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);
    +
    ProductOptions options;
    +options.set_precision_decimals(7);
    +options.set_use_cache(ProductOptions::kDontUseCache);
    +const DecimalNumber product =
    +    CalculateProduct(values, options, /*completion_callback=*/nullptr);
     

    Don'ts

    -

    Note that you should never describe the code -itself. Assume that the person reading the code knows C++ -better than you do, even though he or she does not know -what you are trying to do:

    +

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

    -
    // Now go through the b array and make sure that if i occurs,
    -// the next element is i+1.
    -...        // Geez.  What a useless comment.
    +Compare this:
    +
    +
    // Find the element in the vector.  <-- Bad: obvious!
    +auto iter = std::find(v.begin(), v.end(), element);
    +if (iter != v.end()) {
    +  Process(element);
    +}
    +
    + +To this: + +
    // Process "element" unless it was already processed.
    +auto iter = std::find(v.begin(), v.end(), element);
    +if (iter != v.end()) {
    +  Process(element);
    +}
    +
    + +Self-describing code doesn't need a comment. The comment from +the example above would be obvious: + +
    if (!IsAlreadyProcessed(element)) {
    +  Process(element);
    +}
     
    @@ -4682,10 +4965,11 @@ can easily show longer lines.

    80 characters is the maximum.

    -

    If a comment line contains an example -command or a literal URL longer than 80 characters, that -line may be longer than 80 characters for ease of cut and -paste.

    +

    Comment lines can be longer than 80 +characters if it is not feasible to split them without +harming readability, ease of cut and paste or auto-linking +-- e.g. if a line contains an example command or a literal +URL longer than 80 characters.

    A raw-string literal may have content that exceeds 80 characters. Except for test code, such literals @@ -4804,6 +5088,11 @@ function call.

    Some points to note:

    -

    If some parameters are unused, comment out the -variable name in the function definition:

    +

    Unused parameters that are obvious from context may be omitted:

    -
    // Always have named parameters in interfaces.
    -class Shape {
    +
    class Foo {
    + public:
    +  Foo(Foo&&) = default;
    +  Foo(const Foo&) = default;
    +  Foo& operator=(Foo&&) = default;
    +  Foo& operator=(const Foo&) = default;
    +};
    +
    + +

    Unused parameters that might not be obvious should comment out the variable +name in the function definition:

    + +
    class Shape {
      public:
       virtual void Rotate(double radians) = 0;
     };
     
    -// Always have named parameters in the declaration.
     class Circle : public Shape {
      public:
    -  virtual void Rotate(double radians);
    +  void Rotate(double radians) override;
     };
     
    -// Comment out unused named parameters in definitions.
     void Circle::Rotate(double /*radians*/) {}
     
    @@ -4879,8 +5172,8 @@ ampersand (&) and the variable name.

    auto add_to_x = [&x](int n) { x += n; };

    Short lambdas may be written inline as function arguments.

    -
    std::set<int> blacklist = {7, 8, 9};
    -std::vector<int> digits = {3, 9, 1, 8, 4, 7, 1};
    +
    set<int> blacklist = {7, 8, 9};
    +vector<int> digits = {3, 9, 1, 8, 4, 7, 1};
     digits.erase(std::remove_if(digits.begin(), digits.end(), [&blacklist](int i) {
                    return blacklist.find(i) != blacklist.end();
                  }),
    @@ -4903,7 +5196,7 @@ on each line where appropriate.

    Function calls have the following format:

    -
    bool retval = DoSomething(argument1, argument2, argument3);
    +
    bool result = DoSomething(argument1, argument2, argument3);
     

    If the arguments do not all fit on one line, they @@ -4911,7 +5204,7 @@ should be broken up onto multiple lines, with each subsequent line aligned with the first argument. Do not add spaces after the open paren or before the close paren:

    -
    bool retval = DoSomething(averyveryveryverylongargument1,
    +
    bool result = DoSomething(averyveryveryverylongargument1,
                               argument2, argument3);
     
    @@ -4921,9 +5214,10 @@ lines with a four space indent:

    ... ... if (...) { - DoSomething( + bool result = DoSomething( argument1, argument2, // 4 space indent argument3, argument4); + ... }
    @@ -4941,12 +5235,12 @@ readability due to the complexity or confusing nature of the expressions that make up some arguments, try creating variables that capture those arguments in a descriptive name:

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

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

    -
    bool retval = DoSomething(scores[x] * y + bases[x],  // Score heuristic.
    +
    bool result = DoSomething(scores[x] * y + bases[x],  // Score heuristic.
                               x, y, z);
     
    @@ -5461,24 +5755,32 @@ with subsequent lines indented four spaces.

    -

    There are two acceptable formats for initializer -lists:

    +

    The acceptable formats for initializer lists are:

    -
    // When it all fits on one line:
    -MyClass::MyClass(int var) : some_var_(var), some_other_var_(var + 1) {}
    -
    +
    // When everything fits on one line:
    +MyClass::MyClass(int var) : some_var_(var) {
    +  DoSomething();
    +}
     
    -

    or

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

    - -

    Use common sense and BE CONSISTENT.

    @@ -5811,7 +6111,7 @@ more interesting. Have fun!


    -

    Revision 4.45

    -
    - + + +