From f15e633de5b716a966504e0652fb0c85c2f4f4fb Mon Sep 17 00:00:00 2001 From: Titus Winters Date: Wed, 6 Jul 2016 12:12:21 -0400 Subject: [PATCH] Update to current. This notably includes changes for namespace naming and use of auto, as well as clarification on when comments are necessary and attribute placement. --- cppguide.html | 675 +++++++++++++++++++++++++------------------------- 1 file changed, 333 insertions(+), 342 deletions(-) diff --git a/cppguide.html b/cppguide.html index d09872d95..3539e68c1 100644 --- a/cppguide.html +++ b/cppguide.html @@ -15,7 +15,7 @@

Google C++ Style Guide

-

C++ is the main development language used by +

C++ is one of the main development languages used by many of Google's open-source projects. As every C++ programmer knows, the language has many powerful features, but this power brings with it complexity, which in turn can make @@ -179,36 +179,37 @@

Header Files

Self-contained Headers

-

Header files should be self-contained and end in .h. Files that -are meant for textual inclusion, but are not headers, should end in -.inc. Separate -inl.h headers are disallowed.

+

Header files should be self-contained (compile on their own) and +end in .h. Non-header files that are meant for inclusion +should end in .inc.

-

All header files should be self-contained. In other -words, users and refactoring tools should not have to adhere to special -conditions in order to include the header. Specifically, a -header should have header guards, -should include all other headers it needs, and should not require any -particular symbols to be defined.

- -

There are rare cases where a file is not meant to be self-contained, but -instead is meant to be textually included at a specific point in the code. -Examples are files that need to be included multiple times or -platform-specific extensions that essentially are part of other headers. Such -files should use the file extension .inc.

- -

If a template or inline function is declared in a .h file, -define it in that same file. The definitions of these constructs must -be included into every .cc file that uses them, or the -program may fail to link in some build configurations. Do not move these -definitions to separate -inl.h files.

- -

As an exception, a function template that is explicitly -instantiated for all relevant sets of template arguments, or -that is a private member of a class, may -be defined in the only .cc file that -instantiates the template.

+

All header files should be self-contained. Users and refactoring +tools should not have to adhere to special conditions to include the +header. Specifically, a header should +have header guards and include all +other headers it needs.

+ +

If a template or inline function is declared in a .h +file, that same header should provide its definition. The definitions +of these constructs must be included into every .cc file +that uses them, or the program may fail to link in some build +configurations. Do not move these definitions to separately included +header files (-inl.h); this practice was common in the +past, but is no longer allowed.

+ +

As an exception, a template that is explicitly instantiated for +all relevant sets of template arguments, or that is a private +implementation detail of a class, is allowed to be defined in the one +and only .cc file that instantiates the template.

+ +

There are rare cases where a file is not meant to be +self-contained, but it is meant to be included at a specific point in +the code. Examples are files that need to be included multiple times +or platform-specific implementation details that are essentially part +of other self-contained headers. Such files should use the file +extension .inc.

@@ -509,7 +510,8 @@

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 +encouraged. Do not use using-directives (e.g. +using namespace foo). Do not use inline namespaces.

@@ -732,7 +734,7 @@

Nonmember, Static Member
-

Sometimes it is useful, or even necessary, to define a +

Sometimes it is useful to define a function not bound to a class instance. Such a function can be either a static member or a nonmember function. Nonmember functions should not depend on external @@ -758,7 +760,7 @@

Nonmember, Static Member } -

If you must define a nonmember function and it is only +

If you define a nonmember function and it is only needed in its .cc file, use an unnamed namespace or static linkage (eg static int Foo() @@ -1097,10 +1099,10 @@

Implicit Conversions

Copyable and Movable Types

-

Support copying and/or moving if it makes sense for your type. -Otherwise, disable the implicitly generated special -functions that perform copies and moves.

-
+

Support copying and/or moving if these operations are clear and meaningful +for your type. Otherwise, disable the implicitly generated special functions +that perform copies and moves. +

@@ -1122,15 +1124,15 @@

Copyable and Movable Types

-

Objects of copyable and movable types can be passed and returned -by value, which makes APIs simpler, safer, and more general. -Unlike when passing pointers or references, there's no risk of -confusion over ownership, lifetime, mutability, and similar -issues, and no need to specify them in the contract. It also -prevents non-local interactions between the client and the -implementation, which makes them easier to understand and -maintain. Such objects can be used with generic -APIs that require pass-by-value, such as most containers.

+

Objects of copyable and movable types can be passed and returned by value, +which makes APIs simpler, safer, and more general. Unlike when passing objects +by pointer or reference, there's no risk of confusion over ownership, +lifetime, mutability, and similar issues, and no need to specify them in the +contract. It also prevents non-local interactions between the client and the +implementation, which makes them easier to understand, maintain, and optimize by +the compiler. Further, such objects can be used with generic APIs that +require pass-by-value, such as most containers, and they allow for additional +flexibility in e.g., type composition.

Copy/move constructors and assignment operators are usually easier to define correctly than alternatives @@ -1151,54 +1153,39 @@

Copyable and Movable Types

-

Many types do not need to be copyable, and providing copy -operations for them can be confusing, nonsensical, or outright -incorrect. Copy/assigment operations for base class types are -hazardous, because use of them can lead to -object -slicing. Defaulted or carelessly-implemented copy operations -can be incorrect, and the resulting bugs can be confusing and -difficult to diagnose.

+

Some types do not need to be copyable, and providing copy +operations for such types can be confusing, nonsensical, or outright +incorrect. Types representing singleton objects (Registerer), +objects tied to a specific scope (Cleanup), or closely coupled to +object identity (Mutex) cannot be copied meaningfully. +Copy operations for base class types that are to be used +polymorphically are hazardous, because use of them can lead to +object slicing. +Defaulted or carelessly-implemented copy operations can be incorrect, and the +resulting bugs can be confusing and difficult to diagnose.

Copy constructors are invoked implicitly, which makes the -invocation easy to miss. This may cause confusion, particularly -for programmers used to languages where pass-by-reference is -conventional or mandatory. It may also encourage excessive -copying, which can cause performance problems.

- - +invocation easy to miss. This may cause confusion for programmers used to +languages where pass-by-reference is conventional or mandatory. It may also +encourage excessive copying, which can cause performance problems.

-

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 +

Provide the copy and move operations if their meaning is clear to a casual +user and the copying/moving does not incur unexpected costs. If you define a +copy or move constructor, define the corresponding assignment operator, and +vice-versa. If your type is copyable, do not define move operations unless they +are significantly more efficient than the corresponding copy operations. If your type is not copyable, but the correctness of a move is obvious to users of the type, you may make the type move-only by defining both of the move operations.

If your type provides copy operations, it is recommended that you design -your class so that the default implementation of those operations is correct -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_;
-};
-
+your class so that the default implementation of those operations is correct. +Remember to review the correctness of any defaulted operations as you would any +other code, and to document that your class is copyable and/or cheaply movable +if that's an API guarantee.

class Foo {
  public:
@@ -1218,93 +1205,11 @@ 

Copyable and Movable Types

method, and a protected copy constructor that derived classes can use to implement it.

-

If you do not want to support copy/move operations on -your type, explicitly disable them using = delete or -whatever -other mechanism your project uses. +

If you do not want to support copy/move operations on your type, +explicitly disable them using = delete in +the public: section.

-

- -

Delegating and Inheriting Constructors

- -
-

Use delegating and inheriting -constructors when they reduce code duplication.

-
- -
- -
- -

Delegating and inheriting constructors are two -different features, both introduced in C++11, for -reducing code duplication in constructors. Delegating -constructors allow one of a class's constructors to -forward work to one of the class's other constructors, -using a special variant of the initialization list -syntax. For example:

- -
X::X(const string& name) : name_(name) {
-  ...
-}
-
-X::X() : X("") {}
-
- -

Inheriting constructors allow a derived class to have -its base class's constructors available directly, just as -with any of the base class's other member functions, -instead of having to redeclare them. This is especially -useful if the base has multiple constructors. For -example:

- -
class Base {
- public:
-  Base();
-  Base(int n);
-  Base(const string& s);
-  ...
-};
-
-class Derived : public Base {
- public:
-  using Base::Base;  // Base's constructors are redeclared here.
-};
-
- -

This is especially useful when Derived's -constructors don't have to do anything more than calling -Base's constructors.

-
- -
-

Delegating and inheriting constructors reduce -verbosity and boilerplate, which can improve -readability.

- -

Delegating constructors are familiar to Java -programmers.

-
- -
-

It's possible to approximate the behavior of -delegating constructors by using a helper function.

- -

Inheriting constructors may be confusing if a derived -class introduces new member variables, since the base -class constructor doesn't know about them.

-
- -
-

Use delegating and inheriting constructors when they reduce -boilerplate and improve readability. -Be cautious about inheriting constructors when your derived class has -new member variables. Inheriting constructors may still be appropriate -in that case if you can use in-class member initialization -for the derived class's member variables.

-
-

Structs vs. Classes

@@ -1718,7 +1623,7 @@

Declaration Order

  • Constants (static const data members)
  • -
  • Constructors
  • +
  • Constructors and assignment operators
  • Destructor
  • @@ -2190,8 +2095,6 @@

    Ownership and Smart Pointers

    you need to be compatible with older versions of C++. Never use std::auto_ptr. Instead, use std::unique_ptr.

    - - @@ -2628,9 +2531,10 @@

    Casting

    explicit type conversion is necessary.

      -
    • Convert arithmetic types using brace initialization. This is - the safest approach because code will not compile if conversion can - result in information loss. The syntax is also concise.
    • +
    • Use brace initialization to convert arithmetic types + (e.g. int64{x}). This is the safest approach because code + will not compile if conversion can result in information loss. The + syntax is also concise.
    • @@ -2715,7 +2619,7 @@

      Streams

    • 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 +code, and streams' support for localization is flawed.
    • @@ -3227,7 +3131,8 @@

      Preprocessor Macros

      Be very cautious with macros. Prefer inline functions, -enums, and const variables to macros.

      +enums, and const variables to macros. Don't +use macros to define pieces of a C++ API.

      @@ -3236,6 +3141,26 @@

      Preprocessor Macros

      the code the compiler sees. This can introduce unexpected behavior, especially since macros have global scope.

      +

      The problems introduced by macros are especially severe +when they are used to define pieces of a C++ API, +and still more so for public APIs. Every error message from +the compiler when developers incorrectly use that interface +now must explain how the macros formed the interface. +Refactoring and analysis tools have a dramatically harder +time updating the interface. As a consequence, we +specifically disallow using macros in this way. +For example, avoid patterns like:

      + +
      class WOMBAT_TYPE(Foo) {
      +  // ...
      +
      + public:
      +  EXPAND_PUBLIC_WOMBAT_API(Foo)
      +
      +  EXPAND_WOMBAT_COMPARISONS(Foo, ==, <)
      +};
      +
      +

      Luckily, macros are not nearly as necessary in C++ as they are in C. Instead of using a macro to inline performance-critical code, use an inline function. @@ -3254,7 +3179,10 @@

      Preprocessor Macros

      (like stringifying, concatenation, and so forth) are not available through the language proper. But before using a macro, consider carefully whether there's a non-macro way -to achieve the same result.

      +to achieve the same result. If you need to use a macro to +define an interface, contact +your project leads to request +a waiver of this rule.

      The following usage pattern will avoid many problems with macros; if you use macros, follow it whenever @@ -3347,96 +3275,47 @@

      sizeof

      auto

      -

      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.

      +

      Use auto to avoid type names that are noisy, obvious, +or unimportant - cases where the type doesn't aid in clarity for the +reader. Continue to use manifest type declarations when it helps +readability, and never use auto for anything but local +variables.

      -
      -

      In C++11, a variable whose type is given as auto -will be given a type that matches that of the expression used to -initialize it. You can use auto either to -initialize a variable by copying, or to bind a -reference.

      - -
      vector<string> v;
      -...
      -auto s1 = v[0];  // Makes a copy of v[0].
      -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 -a statement like:

      - -
      sparse_hash_map<string, int>::iterator iter = m.find(val);
      -
      +

      +

        +
      • C++ type names can be long and cumbersome, especially when they +involve templates or namespaces.
      • +
      • When a C++ type name is repeated within a single declaration or a +small code region, the repetition may not be aiding readability.
      • +
      • It is sometimes safer to let the type be specified by the type of +the initialization expression, since that avoids the possibility of +unintended copies or type conversions.
      • +
      +

      - -

      the return type is hard to read, and obscures the -primary purpose of the statement. Changing it to:

      - -
      auto iter = m.find(val);
      -
      - -

      makes it more readable.

      - -

      Without auto we are sometimes forced to -write a type name twice in the same expression, adding no -value for the reader, as in:

      - -
      diagnostics::ErrorStatus* status = new diagnostics::ErrorStatus("xyz");
      -
      - -

      Using auto makes it easier to use -intermediate variables when appropriate, by reducing the -burden of writing their types explicitly.

      -

      Sometimes code is clearer when types are manifest, especially when a variable's initialization depends on -things that were declared far away. In an expression +things that were declared far away. In expressions like:

      - -
      auto i = x.Lookup(key);
      +
      auto foo = x.add_foo();
      +auto i = y.Find(key);
       
      -

      it may not be obvious what i's type is, -if x was declared hundreds of lines earlier.

      +

      It may not be obvious what the resulting types are if the type +of y isn't very well known, or if y was +declared many lines earlier.

      Programmers have to understand the difference between auto and const auto& or they'll get copies when they didn't mean to.

      -

      The interaction between auto and C++11 -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};
      -auto y = {3};
      -
      - -

      mean different things — -x is an int, while -y is a std::initializer_list<int>. -The same applies to other normally-invisible proxy types. -

      -

      If an auto variable is used as part of an interface, e.g. as a constant in a header, then a programmer might change its type while only intending to @@ -3446,12 +3325,47 @@

      auto

      -

      auto is permitted, for local variables -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. -

      +

      auto is permitted, for local variables only, when it +increases readability, particularly as described below. 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.

      + +

      Specific cases where auto is allowed or encouraged: +

        +
      • (Encouraged) For iterators and other long/cluttery type names, particularly +when the type is clear from context (calls +to find, begin, or end for +instance).
      • +
      • (Allowed) When the type is clear from local context (in the same expression +or within a few lines). Initialization of a pointer or smart pointer +with calls +to new +commonly falls into this category, as does use of auto in +a range-based loop over a container whose type is spelled out +nearby.
      • +
      • (Allowed) When the type doesn't matter because it isn't being used for +anything other than equality comparison.
      • +
      • (Encouraged) When iterating over a map with a range-based loop +(because it is often assumed that the correct type +is pair<KeyType,ValueType> whereas it is actually +pair<const KeyType,ValueType>). This is +particularly well paired with local key +and value aliases for .first +and .second (often const-ref). +
        for (const auto& item : some_map) {
        +  const KeyType& key = item.first;
        +  const ValType& value = item.second;
        +  // The rest of the loop can now just refer to key and value,
        +  // a reader can see the types in question, and we've avoided
        +  // the too-common case of extra copies in this iteration.
        +}
        +
        +
      • +
      + +

      +
      @@ -3553,9 +3467,8 @@

      Braced Initializer List

      Lambda expressions

      -

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

      +

      Use lambda expressions where appropriate. Prefer explicit captures +when the lambda will escape the current scope.

      @@ -3571,22 +3484,32 @@

      Lambda expressions

      }); -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: +

      They further allow capturing variables from the enclosing scope either +explicitly by name, or implicitly using a default capture. Explicit captures +require each variable to be listed, as +either a value or reference capture:

      int weight = 3;
       int sum = 0;
      -// Captures `weight` (implicitly) by value and `sum` by reference.
      -std::for_each(v.begin(), v.end(), [=, &sum](int x) {
      +// Captures `weight` by value and `sum` by reference.
      +std::for_each(v.begin(), v.end(), [weight, &sum](int x) {
         sum += weight * x;
       });
       
      + +Default captures implicitly capture any variable referenced in the +lambda body, including this if any members are used: + +
      const std::vector<int> lookup_table = ...;
      +std::vector<int> indices = ...;
      +// Captures `lookup_table` by reference, sorts `indices` by the value
      +// of the associated element in `lookup_table`.
      +std::sort(indices.begin(), indices.end(), [&](int a, int b) {
      +  return lookup_table[a] < lookup_table[b];
      +});
      +
      +

      Lambdas were introduced in C++11 along with a set of utilities for working with function objects, such as the polymorphic wrapper std::function. @@ -3614,19 +3537,20 @@

      Lambda expressions

        -
      • Default captures make it easy to overlook an - implicit capture and use of this. -
      • +
      • Variable capture in lambdas can be a source of dangling-pointer + bugs, particularly if a lambda escapes the current scope.
      • -
      • Variable capture in lambdas can be tricky, and - might be a new source of dangling-pointer bugs, - particularly if a lambda escapes the current scope.
      • +
      • Default captures by value can be misleading because they do not prevent + dangling-pointer bugs. Capturing a pointer by value doesn't cause a deep + copy, so it often has the same lifetime issues as capture by reference. + This is especially confusing when capturing 'this' by value, since the use + of 'this' is often implicit.
      • It's possible for use of lambdas to get out of hand; very long nested anonymous functions can make code harder to understand.
      • - +
      @@ -3634,10 +3558,8 @@

      Lambda expressions

      • Use lambda expressions where appropriate, with formatting as described below.
      • -
      • 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: +
      • Prefer explicit captures if the lambda may escape the current scope. +For example, instead of:
        {
           Foo foo;
           ...
        @@ -3662,6 +3584,15 @@ 

        Lambda expressions

        // reference.
      • +
      • Use default capture by reference ([&]) only when the +lifetime of the lambda is obviously shorter than any potential +captures. +
      • +
      • Use default capture by value ([=]) only as a means of binding a +few variables for a short lambda, where the set of captured +variables is obvious at a glance. Prefer not to write long or +complex lambdas with default capture by value. +
      • Keep unnamed lambdas short. If a lambda body is more than maybe five lines long, prefer to give the lambda a name, or to use a named function instead of a lambda.
      • @@ -4029,10 +3960,59 @@

        C++11

        +
      +

      Nonstandard Extensions

      + +
      +

      Nonstandard extensions to C++ may not be used unless otherwise specified.

      +
      +
      +
      +

      Compilers support various extensions that are not part of standard C++. Such + extensions include GCC's __attribute__, intrinsic functions such + as __builtin_prefetch, designated initializers (e.g. + Foo f = {.field = 3}), inline assembly, __COUNTER__, + __PRETTY_FUNCTION__, compound statement expressions (e.g. + foo = ({ int x; Bar(&x); x }), and the a?:b + syntax.

      +
      + +
      +
        +
      • Nonstandard extensions may provide useful features that do not exist + in standard C++. For example, some people think that designated + initializers are more readable than standard C++ features like + constructors.
      • +
      • Important performance guidance to the compiler can only be specified + using extensions.
      • +
      +
      + +
      +
        +
      • Nonstandard extensions do not work in all compilers. Use of nonstandard + extensions reduces portability of code.
      • +
      • Even if they are supported in all targeted compilers, the extensions + are often not well-specified, and there may be subtle behavior differences + between compilers.
      • +
      • Nonstandard extensions add to the language features that a reader must + know to understand the code.
      • +
      +
      + +
      +

      Do not use nonstandard extensions. You may use portability wrappers that + are implemented using nonstandard extensions, so long as those wrappers + + are provided by a designated project-wide + portability header.

      +
      +
      +

      Aliases

      @@ -4141,7 +4121,7 @@

      Naming

      General Naming Rules

      -

      Names should be descriptive; eschew abbreviation.

      +

      Names should be descriptive; avoid abbreviation.

      @@ -4299,14 +4279,6 @@

      Struct Data Members

      Classes for a discussion of when to use a struct versus a class.

      -

      Global Variables

      - -

      There are no special requirements for global -variables, which should be rare in any case, but if you -use one, consider prefixing it with g_ or -some other marker to easily distinguish it from local -variables.

      -

      Constant Names

      @@ -4375,9 +4347,10 @@

      Function Names

      Namespace Names

      -Namespace names are all lower-case. Top-level -namespace names are based on the project name -. +Namespace names are all lower-case. Top-level namespace names are +based on the project name +. Avoid collisions +between nested namespaces and well-known top-level namespaces.
      @@ -4397,21 +4370,28 @@

      Namespace Names

      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.

      +

      Avoid nested namespaces that match well-known top-level +namespaces. Collisions between namespace names can lead to surprising +build breaks because of name lookup rules. In particular, do not +create any nested std namespaces. Prefer unique project +identifiers +(websearch::index, websearch::index_util) +over collision-prone names like websearch::util.

      + +

      For internal namespaces, be wary of other code being +added to the same internal namespace causing a collision +(internal helpers within a team tend to be related and may lead to +collisions). In such a situation, using the filename to make a unique +internal name is helpful +(websearch::index::frobber_internal for use +in frobber.h)

      Enumerator Names

      -

      Enumerators should be named either like +

      Enumerators (for both scoped and unscoped enums) should be named either like constants or like macros: either kEnumName or ENUM_NAME.

      @@ -4537,9 +4517,13 @@

      Comment Style

      File Comments

      -

      Start each file with license -boilerplate, followed by a description of its -contents.

      +

      Start each file with license boilerplate.

      + +

      File comments describe the contents of a file. If a file declares, +implements, or tests exactly one abstraction that is documented by a comment +at the point of declaration, file comments are not required. All other files +must have file comments.

      +
      @@ -4559,30 +4543,22 @@

      Legal Notice and Author

      File Contents

      -

      Every file should have a comment at the top describing -its contents, unless the specific conditions described below apply.

      - -

      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.

      +

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

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

      -

      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

      -

      Every class definition should have an accompanying comment -that describes what it is for and how it should be used.

      +

      Every non-obvious class declaration should have an accompanying +comment that describes what it is for and how it should be used.

      @@ -4609,28 +4585,34 @@

      Class Comments

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

      +

      When sufficiently separated (e.g. .h and .cc +files), comments describing the use of the class should go together with its +interface definition; comments about the class operation and implementation +should accompany the implementation of the class's methods.

      +

      Function Comments

      -

      Declaration comments describe use of the function; comments -at the definition of a function describe operation.

      +

      Declaration comments describe use of the function (when it is +non-obvious); comments at the definition of a function describe +operation.

      Function Declarations

      -

      Every function declaration should have comments -immediately preceding it that describe what the function -does and how to use it. These comments should be -descriptive ("Opens the file") rather than imperative -("Open the file"); the comment describes the function, it -does not tell the function what to do. In general, these -comments do not describe how the function performs its -task. Instead, that should be left to comments in the -function definition.

      +

      Almost every function declaration should have comments immediately +preceding it that describe what the function does and how to use +it. These comments may be omitted only if the function is simple and +obvious (e.g. simple accessors for obvious properties of the +class). These comments should be descriptive ("Opens the file") +rather than imperative ("Open the file"); the comment describes the +function, it does not tell the function what to do. In general, these +comments do not describe how the function performs its task. Instead, +that should be left to comments in the function definition.

      Types of things to mention in comments at the function declaration:

      @@ -4733,25 +4715,28 @@

      Variable Comments

      Class Data Members

      -

      Each class data member (also called an instance -variable or member variable) should have a comment -describing what it is used for. If the variable can take -sentinel values with special meanings, such as a null -pointer or -1, document this. For example:

      +

      The purpose of each class data member (also called an instance +variable or member variable) must be clear. If there are any +invariants (special values, relationships between members, lifetime +requirements) not clearly expressed by the type and name, they must be +commented. However, if the type and name suffice (int +num_events_;), no comment is needed.

      +

      In particular, add comments to describe the existence and meaning +of sentinel values, such as nullptr or -1, when they are not +obvious. For example:

      private:
      - // Keeps track of the total number of entries in the table.
      - // Used to ensure we do not go over the limit. -1 means
      + // Used to bounds-check table accesses. -1 means
        // that we don't yet know how many entries the table has.
        int num_total_entries_;
       

      Global Variables

      -

      As with data members, all global variables should have -a comment describing what they are and what they are used -for. For example:

      +

      All global variables should have a comment describing what they +are, what they are used for, and (if unclear) why it needs to be +global. For example:

      // The total number of tests cases that we run through in this regression test.
       const int kNumTestCases = 6;
      @@ -5226,10 +5211,10 @@ 

      Function Declarations and Definit
      class Foo {
        public:
      -  Foo(Foo&&) = default;
      -  Foo(const Foo&) = default;
      -  Foo& operator=(Foo&&) = default;
      -  Foo& operator=(const Foo&) = default;
      +  Foo(Foo&&);
      +  Foo(const Foo&);
      +  Foo& operator=(Foo&&);
      +  Foo& operator=(const Foo&);
       };
       
      @@ -5254,6 +5239,12 @@

      Function Declarations and Definit void Circle::Rotate(double) {}

      +

      Attributes, and macros that expand to attributes, appear at the very +beginning of the function declaration or definition, before the +return type:

      +
      MUST_USE_RESULT bool IsOK();
      +
      +

      Lambda Expressions

      @@ -5790,7 +5781,7 @@

      Class Format

      -

      The basic format for a class declaration (lacking the +

      The basic format for a class definition (lacking the comments, see Class Comments for a discussion of what comments are needed) is:

      @@ -6210,6 +6201,6 @@
      -
      +