From c6f57a913e0e178b8ae51364509d1f684c6d4462 Mon Sep 17 00:00:00 2001 From: Daniel Cheng Date: Thu, 31 Jul 2025 15:16:20 -0700 Subject: [PATCH] Update C++ style guide (#937) - Allow coroutine use via libraries approved by project leads - Disallow using a space before `*` and `&` for pointer and reference types - Simplify guidance for using vertical whitespace - Other minor formatting / typography / wording fixes, e.g. adding goodcode/badcode annotations to examples --- cppguide.html | 498 +++++++++++++++++++++++++------------------------- 1 file changed, 253 insertions(+), 245 deletions(-) diff --git a/cppguide.html b/cppguide.html index 2d6f37f..3217b9f 100644 --- a/cppguide.html +++ b/cppguide.html @@ -23,7 +23,7 @@ code more bug-prone and harder to read and maintain.

The goal of this guide is to manage this complexity by describing in detail the dos and don'ts of writing C++ code. These rules exist to -keep the code base manageable while still allowing +keep the codebase manageable while still allowing coders to use C++ language features productively.

Style, also known as readability, is what we call @@ -63,10 +63,10 @@ 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 +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. +Guide doesn't discuss it.

Optimize for the reader, not the writer
Our codebase (and most individual components submitted to it) is @@ -101,7 +101,7 @@ on newer styles over time.
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 same reasons as consistency within our codebase. 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 @@ -240,7 +240,7 @@ project foo should have the following guard:

-
#ifndef FOO_BAR_BAZ_H_
+
#ifndef FOO_BAR_BAZ_H_
 #define FOO_BAR_BAZ_H_
 
 ...
@@ -275,7 +275,7 @@ includes bar.h.

A "forward declaration" is a declaration of an entity without an associated definition.

-
// In a C++ source file:
+
// In a C++ source file:
 class B;
 void FuncInB();
 extern int variable_in_b;
@@ -319,7 +319,7 @@ ABSL_DECLARE_FLAG(flag_in_b);
   Replacing an #include with a forward
   declaration can silently change the meaning of
   code:
-
// b.h:
+
// b.h:
 struct B {};
 struct D : B {};
 
@@ -455,7 +455,7 @@ directory without use of UNIX directory aliases
 google-awesome-project/src/base/logging.h
 should be included as:

-
#include "base/logging.h"
+
#include "base/logging.h"
 

Headers should only be included using an angle-bracketed path if the library @@ -463,11 +463,11 @@ requires you to do so. In particular, the following headers require angle brackets:

    -
  • C and C++ standard library headers (e.g. <stdlib.h> +
  • C and C++ standard library headers (e.g., <stdlib.h> and <string>).
  • -
  • POSIX, Linux, and Windows system headers (e.g. <unistd.h> +
  • POSIX, Linux, and Windows system headers (e.g., <unistd.h> and <windows.h>).
  • -
  • In rare cases, third_party libraries (e.g. <Python.h>).
  • +
  • In rare cases, third_party libraries (e.g., <Python.h>).

In dir/foo.cc or @@ -535,7 +535,7 @@ this rule and should be fixed when convenient.

google-awesome-project/src/foo/internal/fooserver.cc might look like this:

-
#include "foo/server/fooserver.h"
+
#include "foo/server/fooserver.h"
 
 #include <sys/types.h>
 #include <unistd.h>
@@ -555,13 +555,11 @@ conditional includes. Such code can put conditional
 includes after other includes. Of course, keep your
 system-specific code small and localized. Example:

-
#include "foo/public/fooserver.h"
+
#include "foo/public/fooserver.h"
 
-#include "base/port.h"  // For LANG_CXX11.
-
-#ifdef LANG_CXX11
-#include <initializer_list>
-#endif  // LANG_CXX11
+#ifdef _WIN32
+#include <windows.h>
+#endif  // _WIN32
 

Scoping

@@ -640,7 +638,7 @@ namespaces, this can add a lot of clutter.

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

-
// In the .h file
+
// In the .h file
 namespace mynamespace {
 
 // All declarations are within the namespace scope.
@@ -654,7 +652,7 @@ class MyClass {
 }  // namespace mynamespace
 
-
// In the .cc file
+
// In the .cc file
 namespace mynamespace {
 
 // Definition of functions is within scope of the namespace.
@@ -668,7 +666,7 @@ void MyClass::Foo() {
   

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

-
#include "a.h"
+
#include "a.h"
 
 ABSL_FLAG(bool, someflag, false, "a flag");
 
@@ -710,25 +708,29 @@ using namespace foo;
   
  • Do not use Namespace aliases at namespace scope in header files except in explicitly marked internal-only namespaces, because anything imported into a namespace - in a header file becomes part of the public - API exported by that file.

    + in a header file becomes part of the public API exported by that file. + Namespace aliases can be used when those conditions don't apply, but + they must have appropriate names.

    -
    // Shorten access to some commonly used names in .cc files.
    -namespace baz = ::foo::bar::baz;
    -
    - -
    // Shorten access to some commonly used names (in a .h file).
    +
    // In a .h file, an alias must not be a separate API, or must be hidden in an
    +// implementation detail.
     namespace librarian {
    +
     namespace internal {  // Internal, not part of the API.
     namespace sidetable = ::pipeline_diagnostics::sidetable;
     }  // namespace internal
     
     inline void my_inline_function() {
    -  // namespace alias local to a function (or method).
    +  // Local to a function.
       namespace baz = ::foo::bar::baz;
       ...
     }
    +
     }  // namespace librarian
    +
    + +
    // Remove uninteresting parts of some commonly used names in .cc files.
    +namespace sidetable = ::pipeline_diagnostics::sidetable;
     
  • Do not use inline namespaces.
  • @@ -744,7 +746,7 @@ using ::absl::container_internal::ImplementationDetail;

    Note that there is still a risk of collision between libraries within a nested internal namespace, so give each library within a namespace a unique internal namespace by adding the library's - filename. E.g. gshoe/widget.h would use + filename. For example, gshoe/widget.h would use gshoe::internal_widget as opposed to just gshoe::internal.

    @@ -779,7 +781,7 @@ Do not use internal linkage in .h files.

    Format unnamed namespaces like named namespaces. In the terminating comment, leave the namespace name empty:

    -
    namespace {
    +
    namespace {
     ...
     }  // namespace
     
    @@ -834,7 +836,7 @@ be used instead of declaration and assignment, e.g.,:

    i = f(); // Bad -- initialization separate from declaration.
    -
    int i = f();  // Good -- declaration has initialization.
    +
    int i = f();  // Good -- declaration has initialization.
     
    @@ -843,7 +845,7 @@ i = f(); // Bad -- initialization separate from declaration. f(jobs); // Bad -- declaration separate from use.
    -
    int jobs = NumJobs();
    +
    int jobs = NumJobs();
     f(jobs);      // Good -- declaration immediately (or closely) followed by use.
     
    @@ -852,15 +854,15 @@ v.push_back(1); // Prefer initializing using brace initialization. v.push_back(2);
    -
    std::vector<int> v = {1, 2};  // Good -- v starts initialized.
    +
    std::vector<int> v = {1, 2};  // Good -- v starts initialized.
     

    Variables needed for if, while and for statements should normally be declared within those statements, so that such variables are confined -to those scopes. E.g.:

    +to those scopes. For example:

    -
    while (const char* p = strchr(str, '/')) str = p + 1;
    +
    while (const char* p = strchr(str, '/')) str = p + 1;
     

    There is one caveat: if the variable is an object, its @@ -878,7 +880,7 @@ for (int i = 0; i < 1000000; ++i) {

    It may be more efficient to declare such a variable used in a loop outside that loop:

    -
    Foo f;  // My ctor and dtor get called once each.
    +
    Foo f;  // My ctor and dtor get called once each.
     for (int i = 0; i < 1000000; ++i) {
       f.DoSomething(i);
     }
    @@ -952,7 +954,7 @@ objects with static storage duration if they are trivially destructible.
     Fundamental types (like pointers and int) are trivially
     destructible, as are arrays of trivially destructible types. Note that
     variables marked with constexpr are trivially destructible.

    -
    const int kNum = 10;  // Allowed
    +
    const int kNum = 10;  // Allowed
     
     struct X { int n; };
     const X kX[] = {{1}, {2}, {3}};  // Allowed
    @@ -1029,7 +1031,7 @@ it is forbidden. However, we do permit it if no aspect of the program depends
     on the sequencing of this initialization with respect to all other
     initializations. Under those restrictions, the ordering of the initialization
     does not make an observable difference. For example:

    -
    int p = getpid();  // Allowed, as long as no other static variable
    +
    int p = getpid();  // Allowed, as long as no other static variable
                        // uses p in its own initialization.

    Dynamic initialization of static local variables is allowed (and common).

    @@ -1088,7 +1090,7 @@ attribute. Prefer

    Variables can be declared with the thread_local specifier:

    -
    thread_local Foo foo = ...;
    +
    thread_local Foo foo = ...;
     

    Such a variable is actually a collection of objects, so that when different threads access it, they are actually accessing different objects. @@ -1158,7 +1160,7 @@ get a particularly hard to diagnose use-after-free.

    constinit (or constexpr, but that should be rare):

    -
       constinit thread_local Foo foo = ...;
    +  
       constinit thread_local Foo foo = ...;
       

    thread_local variables inside a function have no initialization @@ -1167,7 +1169,7 @@ get a particularly hard to diagnose use-after-free.

    namespace-scope thread_local by defining a function or static method that exposes it:

    -
    Foo& MyThreadLocalFoo() {
    +
    Foo& MyThreadLocalFoo() {
       thread_local Foo result = ComplicatedInitialization();
       return result;
     }
    @@ -1272,7 +1274,7 @@ or 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
     list initialization syntax:

    -
    class Foo {
    +
    class Foo {
       explicit Foo(int x, double y);
       ...
     };
    @@ -1440,7 +1442,7 @@ moves. Explicitly declaring or deleting all four copy/move operations is
     permitted, but not required. If you provide a copy or move assignment operator,
     you must also provide the corresponding constructor.

    -
    class Copyable {
    +
    class Copyable {
      public:
       Copyable(const Copyable& other) = default;
       Copyable& operator=(const Copyable& other) = default;
    @@ -1682,7 +1684,7 @@ creating objects of user-defined types.

  • Finding the call sites for overloaded operators may require a search tool that's aware of C++ syntax, rather - than e.g., grep.
  • + than, e.g., grep.
  • If you get the argument type of an overloaded operator wrong, you may get a different overload rather than a @@ -1834,8 +1836,8 @@ following order:

    Do not put large method definitions inline in the class definition. Usually, only trivial or performance-critical, and very short, methods may be -defined inline. See Inline -Functions for more details.

    +defined inline. See Defining +Functions in Header Files for more details.

    Functions

    @@ -1923,7 +1925,7 @@ takes const char*. However, in this case consider instead.

    -
    class MyClass {
    +
    class MyClass {
      public:
       void Analyze(const std::string &text);
       void Analyze(const char *text, size_t textlen);
    @@ -1952,9 +1954,14 @@ function.

    between variants. These overloads may vary in types, qualifiers, or argument count. However, a reader of such a call must not need to know which member of the overload set is chosen, only that something -from the set is being called. If you can document all entries in the -overload set with a single comment in the header, that is a good sign -that it is a well-designed overload set.

    +from the set is being called.

    + +

    To reflect this unified design, prefer a single, comprehensive "umbrella" +comment that documents the entire overload set and is placed before the first +declaration.

    + +

    Where a reader might have difficulty connecting the umbrella +comment to a specific overload, it's okay to have a comment for specific overloads.

    Default Arguments

    @@ -2014,13 +2021,13 @@ doubt, use overloads.

    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);
    +
    int foo(int x);
     

    The newer form 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;
    +
    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 @@ -2038,11 +2045,11 @@ doubt, use overloads.

    after the function's parameter list has already appeared. This is particularly true when the return type depends on template parameters. For example:

    -
        template <typename T, typename U>
    +  
        template <typename T, typename U>
         auto add(T t, U u) -> decltype(t + u);
       
    versus -
        template <typename T, typename U>
    +  
        template <typename T, typename U>
         decltype(declval<T&>() + declval<U&>()) add(T t, U u);
       
    @@ -2050,7 +2057,7 @@ doubt, use overloads.

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

    -

    Existing code bases have an enormous number of function +

    Existing codebases 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.

    @@ -2187,7 +2194,7 @@ or passing a pointer or reference without transferring ownership. Prefer to use std::unique_ptr to make ownership transfer explicit. For example:

    -
    std::unique_ptr<Foo> FooFactory();
    +
    std::unique_ptr<Foo> FooFactory();
     void FooConsumer(std::unique_ptr<Foo> ptr);
     
    @@ -2222,7 +2229,7 @@ tool.

    how to run cpplint.py from their project tools. If the project you are contributing to does not, you can download - + cpplint.py separately.

    @@ -2270,7 +2277,7 @@ rules apply. Such a reference is called a forwarding reference.

    std::unique_ptr.
  • Forwarding references which - use the rvalue reference token, make it possible to write a + use the rvalue reference token 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 and/or const. @@ -2330,7 +2337,7 @@ of friend is to have a Foo so that it can construct the inner state of Foo correctly, without exposing this state to the world. In some cases it may be useful to -make a unittest class a friend of the class it tests.

    +make a unit test class a friend of the class it tests.

    Friends extend, but do not break, the encapsulation boundary of a class. In some cases this is better than @@ -2523,7 +2530,7 @@ move-constructing objects), or on whether allocation can throw standard default allocation). Note in many cases the only possible cause for an exception is allocation failure (we believe move constructors should not throw except due to -allocation failure), and there are many applications where it’s +allocation failure), and there are many applications where it's appropriate to treat memory exhaustion as a fatal error rather than an exceptional condition that your program should attempt to recover from. Even for other @@ -2531,7 +2538,7 @@ potential failures you should prioritize interface simplicity over supporting all possible exception throwing scenarios: instead of writing a complicated noexcept clause that depends on whether a hash function can throw, for example, -simply document that your component doesn’t support hash +simply document that your component doesn't support hash functions throwing and make it unconditionally noexcept.

    @@ -2562,7 +2569,7 @@ relationship between objects and their mocks.

    RTTI is useful when considering multiple abstract objects. Consider

    -
    bool Base::Equal(Base* other) = 0;
    +
    bool Base::Equal(Base* other) = 0;
     bool Derived::Equal(Base* other) {
       Derived* that = dynamic_cast<Derived*>(other);
       if (that == nullptr)
    @@ -2585,7 +2592,7 @@ must be examined when making further changes.

    RTTI has legitimate uses but is prone to abuse, so you must be careful when using it. You may use it freely in -unittests, but avoid it when possible in other code. In +unit tests, but avoid it when possible in other code. In particular, think twice before using RTTI in new code. If you find yourself needing to write code that behaves differently based on the class of an object, consider one @@ -2671,8 +2678,8 @@ casts when explicit type conversion is necessary. will not compile if conversion can result in information loss. The syntax is also concise.

  • -
  • When explicitly converting to a class type, use a function-style cast. - E.g. prefer std::string(some_cord) to +
  • When explicitly converting to a class type, use a function-style cast; + e.g., prefer std::string(some_cord) to static_cast<std::string>(some_cord).
  • Use absl::implicit_cast @@ -2775,7 +2782,7 @@ develop experience with it in order to use it effectively.
  • 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 +large codebase, it can consume as much as 20% of the parsing and semantic analysis time.
  • @@ -2853,7 +2860,7 @@ needs the result of the postfix increment/decrement expression.

    In APIs, use const whenever it makes sense. constexpr is a better choice for some uses of -const.

    +const.

    Declared variables and parameters can be preceded @@ -3015,7 +3022,7 @@ The standard library header <stdint.h> defines types like int16_t, uint32_t, int64_t, etc. You should always use those in preference to short, unsigned -long long and the like, when you need a guarantee +long long, and the like, when you need a guarantee on the size of an integer. Prefer to omit the std:: prefix for these types, as the extra 5 characters do not merit the added clutter. Of the built-in integer types, only @@ -3114,7 +3121,7 @@ single processor.

  • Use braced-initialization as needed to create 64-bit constants. For example: -
    int64_t my_value{0x123456789};
    +
    int64_t my_value{0x123456789};
     uint64_t my_mask{uint64_t{3} << 48};
     
  • @@ -3236,14 +3243,14 @@ to any particular variable, such as code that manages an external or internal data format where a variable of an appropriate C++ type is not convenient.

    -
    MyStruct data;
    +
    MyStruct data;
     memset(&data, 0, sizeof(data));
     
    memset(&data, 0, sizeof(MyStruct));
     
    -
    if (raw_size < sizeof(int)) {
    +
    if (raw_size < sizeof(int)) {
       LOG(ERROR) << "compressed record not big enough for count: " << raw_size;
       return false;
     }
    @@ -3300,7 +3307,7 @@ auto d{42};   // d is an int, not a std::initializer_list<int>
         rather than by an explicit auto. Confusingly,
         trailing return type syntax for functions
         also uses auto in the return-type position, but that doesn't
    -    rely on type deduction; it's just an alternate syntax for an explicit
    +    rely on type deduction; it's just an alternative syntax for an explicit
         return type.
       
    Generic lambdas
    @@ -3434,8 +3441,8 @@ std::array numbers = {4, 8, 15, 16, 23, 42}; Note that class template argument deduction is also subject to a separate style rule.

    -

    Do not use decltype(auto) if a simpler option will work, - because it's a fairly obscure feature, so it has a high cost in code +

    Do not use decltype(auto) if a simpler option will work; + because it's a fairly obscure feature, it has a high cost in code clarity.

    Return type deduction

    @@ -3485,7 +3492,7 @@ std::array numbers = {4, 8, 15, 16, 23, 42}; field names. We recommend using a comment to indicate the name of the underlying field, if it doesn't match the name of the binding, using the same syntax as for function parameter comments:

    -
    auto [/*field_name1=*/bound_name1, /*field_name2=*/bound_name2] = ...
    +
    auto [/*field_name1=*/bound_name1, /*field_name2=*/bound_name2] = ...

    As with function parameter comments, this can enable tools to detect if you get the order of the fields wrong.

    @@ -3603,7 +3610,7 @@ when the lambda will escape the current scope.

    function objects. They're often useful when passing functions as arguments. For example:

    -
    std::sort(v.begin(), v.end(), [](int x, int y) {
    +
    std::sort(v.begin(), v.end(), [](int x, int y) {
       return Weight(x) < Weight(y);
     });
     
    @@ -3613,7 +3620,7 @@ 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 weight = 3;
     int sum = 0;
     // Captures `weight` by value and `sum` by reference.
     std::for_each(v.begin(), v.end(), [weight, &sum](int x) {
    @@ -3625,7 +3632,7 @@ std::for_each(v.begin(), v.end(), [weight, &sum](int 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 = ...;
    +
    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`.
    @@ -3637,7 +3644,7 @@ std::sort(indices.begin(), indices.end(), [&](int a, int b) {
     

    A variable capture can also have an explicit initializer, which can be used for capturing move-only variables by value, or for other situations not handled by ordinary reference or value captures:

    -
    std::unique_ptr<Foo> foo = ...;
    +  
    std::unique_ptr<Foo> foo = ...;
     [foo = std::move(foo)] () {
       ...
     }
    @@ -3717,7 +3724,7 @@ For example, instead of: // and the enclosing object could have been destroyed.
    prefer to write: -
    {
    +
    {
       Foo foo;
       ...
       executor->Schedule([&foo] { Frobnicate(foo); })
    @@ -3800,7 +3807,7 @@ over a large number of uses.

    complicated template techniques; think about whether the average member of your team will be able to understand your code well enough to maintain it after you switch to another project, or whether a -non-C++ programmer or someone casually browsing the code base will be +non-C++ programmer or someone casually browsing the codebase will be able to understand the error messages or trace the flow of a function they want to call. If you're using recursive template instantiations or type lists or metafunctions or expression templates, or relying on @@ -3940,23 +3947,68 @@ and import.

    Modules are a big shift in how C++ is written and compiled, and we are still assessing how they may fit into Google's C++ ecosystem in the future. Furthermore, they are not currently well-supported by our -build-systems, compilers, and other tooling, and need further -exploration as to the best-practices when writing and using them.

    +build systems, compilers, and other tooling, and need further +exploration as to the best practices when writing and using them.

    Coroutines

    -

    Do not use coroutines (yet).

    -

    Do not include the <coroutine> header, -or use the co_await, co_yield, -or co_return keywords.

    +

    Only use C++20 coroutines via libraries that have been + approved by your project leads.

    -

    NOTE: this ban is expected to be temporary, while further -guidance is being developed. +

    +

    C++20 introduced +coroutines: +functions that can suspend and resume +executing later. They are especially convenient for asynchronous +programming, where they can provide substantial improvements over +traditional callback-based frameworks.

    -

    +

    Unlike most other programming languages (Kotlin, Rust, TypeScript, etc.), +C++ does not provide a concrete implementation of coroutines. +Instead, it requires users to implement their own awaitable type (using a + + promise type) which determines coroutine parameter types, how coroutines +are executed, and allows running user-defined code during different stages +of their execution.

    + +

    +
      +
    • Coroutines can be used to implement safe and efficient libraries suited + for specific tasks, such as asynchronous programming.
    • +
    • Coroutines are syntactically almost identical to non-coroutine functions, + which can make them substantially more readable than alternatives.
    • +
    • The high degree of customization makes it possible to insert more + detailed debugging information into coroutines, compared to + alternatives.
    • +
    + +

    +
      +
    • There is no standard coroutine promise type, and each user-defined + implementation is likely going to be unique in some aspect.
    • +
    • Because of load-bearing interactions between the return type, the + various customizable hooks in the promise type, and compiler-generated + code, coroutine semantics are extremely difficult to deduce from reading + user code.
    • +
    • The many customizable aspects of coroutines introduce a large number + of pitfalls, especially around dangling references and race + conditions.
    • +
    + +

    In summary, designing a high-quality and interoperable coroutine library +requires a large amount of difficult work, careful thought, and extensive +documentation.

    + +

    + + + +

    Use only coroutine libraries that have been approved for + project-wide use by your project leads. Do not roll your own promise or + awaitable types.

    Boost

    @@ -4067,7 +4119,7 @@ the future.

    As with Boost, some modern C++ library functionality encourages coding practices that hamper -readability—for example by removing +readability — for example by removing checked redundancy (such as type names) that may be helpful to readers, or by encouraging template metaprogramming. Other extensions duplicate functionality @@ -4126,7 +4178,7 @@ and conversion costs.

  • 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 +
  • Nonstandard extensions add features to the language that a reader must know to understand the code.
  • Nonstandard extensions require additional work to port across architectures.
  • @@ -4144,7 +4196,7 @@ and conversion costs.

    There are several ways to create names that are aliases of other entities:

    -
    using Bar = Foo;
    +
    using Bar = Foo;
     typedef Foo Bar;  // But prefer `using` in C++ code.
     using ::other_namespace::Foo;
     using enum MyEnumType;  // Creates aliases for all enumerators in MyEnumType.
    @@ -4176,11 +4228,11 @@ using enum MyEnumType;  // Creates aliases for all enumerators in MyEnumType.
           changes difficult.
         
  • It can be tempting to create a public alias that is only intended for use in the implementation, without considering its impact on the API, or on maintainability.
  • -
  • Aliases can create risk of name collisions
  • -
  • Aliases can reduce readability by giving a familiar construct an unfamiliar name
  • +
  • Aliases can create risk of name collisions.
  • +
  • Aliases can reduce readability by giving a familiar construct an unfamiliar name.
  • Type aliases can create an unclear API contract: it is unclear whether the alias is guaranteed to be identical to the type it aliases, - to have the same API, or only to be usable in specified narrow ways
  • + to have the same API, or only to be usable in specified narrow ways.

    @@ -4192,11 +4244,11 @@ it's currently aliased to, or whether a more limited compatibility is intended. This lets the user know whether they can treat the types as substitutable or whether more specific rules must be followed, and can help the implementation retain some degree of freedom to change the alias.

    -

    Don't put namespace aliases in your public API. (See also Namespaces). +

    Don't put namespace aliases in your public API. (See also Namespaces.)

    For example, these aliases document how they are intended to be used in client code:

    -
    namespace mynamespace {
    +
    namespace mynamespace {
     // Used to store field measurements. DataPoint may change from Bar* to some internal type.
     // Client code should treat it as an opaque pointer.
     using DataPoint = ::foo::Bar*;
    @@ -4218,9 +4270,9 @@ typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator&g
     

    However, local convenience aliases are fine in function definitions, private - sections of classes, explicitly marked internal namespaces, and in .cc files:

    + sections of classes, explicitly-marked internal namespaces, and in .cc files:

    -
    // In a .cc file
    +
    // In a .cc file
     using ::foo::Bar;
     
    @@ -4231,7 +4283,7 @@ have a default case (in the case of an enumerated value, the compiler will warn you if any values are not handled). If the default case should never execute, treat this as an error. For example: -

    switch (var) {
    +

    switch (var) {
       case 0: {
         ...
         break;
    @@ -4252,7 +4304,7 @@ be placed at a point of execution where a fall-through to the next case label
     occurs. A common exception is consecutive case labels without intervening code,
     in which case no annotation is needed.

    -
    switch (x) {
    +
    switch (x) {
       case 41:  // No annotation needed here.
       case 43:
         if (dont_be_picky) {
    @@ -4340,8 +4392,8 @@ parameter.

    "vocabulary" names are reused so widely that they are always in context. These names tend to be short or even abbreviated and their full meaning comes from explicit long-form documentation rather than from just comments on their -definition and the words within the names. E.g. absl::Status has a -dedicated +definition and the words within the names. For example, absl::Status +has a dedicated page in a devguide, @@ -4350,7 +4402,7 @@ often, but if you do, get additional design review to make sure the chosen names work well when used widely.

    -
    class MyClass {
    +
    class MyClass {
      public:
       int CountFooErrors(const std::vector<Foo>& foos) {
         int n = 0;  // Clear meaning given limited scope and context
    @@ -4435,7 +4487,7 @@ 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
    +
    // classes and structs
     class UrlTable { ...
     class UrlTableTester { ...
     struct UrlTableProperties { ...
    @@ -4466,7 +4518,7 @@ Concept names follow the same rules as type names.
     
     

    For example:

    -
    std::string table_name;  // OK - snake_case.
    +
    std::string table_name;  // OK - snake_case.
     
    std::string tableName;   // Bad - mixed case.
    @@ -4480,7 +4532,7 @@ trailing underscore. The exception to this is static constant
     class members, which should follow the rules for
     naming constants.

    -
    class TableInfo {
    +
    class TableInfo {
      public:
       ...
       static const int kTableVersion = 3;  // OK - constant naming.
    @@ -4498,7 +4550,7 @@ class members, which should follow the rules for
     are named like ordinary nonmember variables. They do not have
     the trailing underscores that data members in classes have.

    -
    struct UrlTableProperties {
    +
    struct UrlTableProperties {
       std::string name;
       int num_entries;
       static Pool<UrlTableProperties>* pool;
    @@ -4517,7 +4569,7 @@ the duration of the program, are named with a leading "k" followed
     by mixed case. Underscores can be used as separators in the rare cases
     where capitalization cannot be used for separation. For example:

    -
    const int kDaysInAWeek = 7;
    +
    const int kDaysInAWeek = 7;
     const int kAndroid8_0_0 = 24;  // Android 8.0.0
     
    @@ -4528,7 +4580,7 @@ class data members and those in templates where different instantiations of the may have different values. This convention is optional for variables of other storage classes, e.g., automatic variables; otherwise the usual variable naming rules apply. For example:

    -
    void ComputeFoo(absl::string_view suffix) {
    +
    void ComputeFoo(absl::string_view suffix) {
       // Either of these is acceptable.
       const absl::string_view kPrefix = "prefix";
       const absl::string_view prefix = "prefix";
    @@ -4545,26 +4597,23 @@ e.g., automatic variables; otherwise the usual variable naming rules apply. For
     
     

    Function Names

    -

    Regular functions have mixed case; accessors and mutators may be named -like variables.

    +

    Ordinarily, functions follow PascalCase: +start with a capital letter and have a capital letter for each new word.

    -

    Ordinarily, functions should start with a capital letter and have a -capital letter for each new word.

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

    (The same naming rule applies to class- and namespace-scope +

    The same naming rule applies to class- and namespace-scope constants that are exposed as part of an API and that are intended to look like functions, because the fact that they're objects rather than functions -is an unimportant implementation detail.)

    +is an unimportant implementation detail.

    -

    Accessors and mutators (get and set functions) may be named like -variables. These often correspond to actual member variables, but this is -not required. For example, int count() and void -set_count(int count).

    +

    Accessors and mutators (get and set functions) may be named like variables, +in snake_case. These often correspond to actual member variables, +but this is not required. For example, int count() and +void set_count(int count).

    Namespace Names

    @@ -4594,7 +4643,7 @@ namespaces do not protect from collisions with names in other namespaces -
    enum class UrlTableError {
    +
    enum class UrlTableError {
       kOk = 0,
       kOutOfMemory,
       kMalformedInput,
    @@ -4636,7 +4685,7 @@ of macros; in general macros should not be used.
     However, if they are absolutely needed, then they should be
     named with all capitals and underscores, and with a project-specific prefix.

    -
    #define MYPROJECT_ROUND(x) ...
    +
    #define MYPROJECT_ROUND(x) ...
     

    Aliases

    @@ -4731,7 +4780,7 @@ author line.

    accompanying comment that describes what it is for and how it should be used.

    -
    // Iterates over the contents of a GargantuanTable.
    +
    // Iterates over the contents of a GargantuanTable.
     // Example:
     //    std::unique_ptr<GargantuanTableIterator> iter = table->NewIterator();
     //    for (iter->Seek("foo"); !iter->done(); iter->Next()) {
    @@ -4795,7 +4844,7 @@ declaration:

    if it is.
  • For each output or input/output argument, what happens to any state that argument - is in. (E.g. is the state appended to or overwritten?). + is in (e.g., is the state appended to or overwritten?).
  • If there are any performance implications of how a function is used.
  • @@ -4803,7 +4852,7 @@ declaration:

    Here is an example:

    -
    // Returns an iterator for this table, positioned at the first entry
    +
    // Returns an iterator for this table, positioned at the first entry
     // lexically greater than or equal to `start_word`. If there is no
     // such entry, returns a null pointer. The client must not use the
     // iterator after the underlying GargantuanTable has been destroyed.
    @@ -4872,7 +4921,7 @@ num_events_;), no comment is needed.

    of sentinel values, such as nullptr or -1, when they are not obvious. For example:

    -
    private:
    +
    private:
      // Used to bounds-check table accesses. -1 means
      // that we don't yet know how many entries the table has.
      int num_total_entries_;
    @@ -4884,7 +4933,7 @@ obvious. For example:

    are, what they are used for, and (if unclear) why they need to be global. For example:

    -
    // The total number of test cases that we run through in this regression test.
    +
    // The total number of test cases that we run through in this regression test.
     const int kNumTestCases = 6;
     
    @@ -4938,7 +4987,7 @@ const DecimalNumber product = CalculateProduct(values, 7, false, nullptr);

    versus:

    -
    ProductOptions options;
    +
    ProductOptions options;
     options.set_precision_decimals(7);
     options.set_use_cache(ProductOptions::kDontUseCache);
     const DecimalNumber product =
    @@ -4949,8 +4998,8 @@ const DecimalNumber product =
     
     

    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.

    +C++ well. Instead, provide higher-level comments that describe why +the code does what it does, or make the code self-describing.

    Compare this: @@ -4962,7 +5011,7 @@ if (std::find(v.begin(), v.end(), element) != v.end()) { To this: -
    // Process "element" unless it was already processed.
    +
    // Process "element" unless it was already processed.
     if (std::find(v.begin(), v.end(), element) != v.end()) {
       Process(element);
     }
    @@ -4971,7 +5020,7 @@ if (std::find(v.begin(), v.end(), element) != v.end()) {
     

    Self-describing code doesn't need a comment. The comment from the example above would be obvious:

    -
    if (!IsAlreadyProcessed(element)) {
    +
    if (!IsAlreadyProcessed(element)) {
       Process(element);
     }
     
    @@ -5002,23 +5051,18 @@ goal.

    Use TODO comments for code that is temporary, a short-term solution, or good-enough but not perfect.

    -

    TODOs should include the string -TODO in all caps, followed by the +

    -bug ID, name, e-mail address, or other -identifier +

    TODOs should include the string +TODO in all caps, followed by the bug ID, name, e-mail address, or other identifier of the person or issue with the best context about the problem referenced by the TODO. -

    - -
    -
    // TODO: bug 12345678 - Remove this after the 2047q4 compatibility window expires.
    +

    // TODO: bug 12345678 - Remove this after the 2047q4 compatibility window expires.
     // TODO: example.com/my-design-doc - Manually fix up this code the next time it's touched.
     // TODO(bug 12345678): Update this list after the Foo service is turned down.
     // TODO(John): Use a "\*" here for concatenation operator.
     
    -

    If your TODO is of the form "At a future date do something" make sure that you either include a @@ -5026,6 +5070,8 @@ very specific date ("Fix by November 2005") or a very specific event ("Remove this code when all clients can handle XML responses.").

    +
    +

    Formatting

    Coding style and formatting are pretty arbitrary, but a @@ -5090,8 +5136,8 @@ can easily show longer lines.

  • a string literal that cannot easily be wrapped at 80 columns. This may be because it contains URIs or other semantically-critical pieces, - or because the literal contains an embedded language, or a multiline - literal whose newlines are significant like help messages. + or because the literal contains an embedded language, or because it is a + multiline literal whose newlines are significant, such as help messages. In these cases, breaking up the literal would reduce readability, searchability, ability to click links, etc. Except for test code, such literals should appear at namespace scope near the top of a @@ -5105,9 +5151,9 @@ can easily show longer lines.

  • an include statement.
  • -
  • a header guard
  • +
  • a header guard.
  • -
  • a using-declaration
  • +
  • a using-declaration.
  • Non-ASCII Characters

    @@ -5121,7 +5167,7 @@ rare. However, in certain cases it is appropriate to include such words in your code. For example, if your code parses data files from foreign sources, it may be appropriate to hard-code the non-ASCII string(s) used in -those data files as delimiters. More commonly, unittest +those data files as delimiters. More commonly, unit test code (which does not need to be localized) might contain non-ASCII strings. In such cases, you should use UTF-8, since that is an encoding @@ -5166,7 +5212,7 @@ not fit on a single line as you would wrap arguments in a

    Functions look like this:

    -
    ReturnType ClassName::FunctionName(Type par_name1, Type par_name2) {
    +
    ReturnType ClassName::FunctionName(Type par_name1, Type par_name2) {
       DoSomething();
       ...
     }
    @@ -5174,7 +5220,7 @@ not fit on a single line as you would wrap arguments in a
     
     

    If you have too much text to fit on one line:

    -
    ReturnType ClassName::ReallyLongFunctionName(Type par_name1, Type par_name2,
    +
    ReturnType ClassName::ReallyLongFunctionName(Type par_name1, Type par_name2,
                                                  Type par_name3) {
       DoSomething();
       ...
    @@ -5183,7 +5229,7 @@ not fit on a single line as you would wrap arguments in a
     
     

    or if you cannot fit even the first parameter:

    -
    ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
    +
    ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
         Type par_name1,  // 4 space indent
         Type par_name2,
         Type par_name3) {
    @@ -5231,9 +5277,9 @@ not fit on a single line as you would wrap arguments in a
       
  • Wrapped parameters have a 4 space indent.
  • -

    Unused parameters that are obvious from context may be omitted:

    +

    Unused parameters that are obvious from context may omit the name:

    -
    class Foo {
    +
    class Foo {
      public:
       Foo(const Foo&) = delete;
       Foo& operator=(const Foo&) = delete;
    @@ -5243,7 +5289,7 @@ not fit on a single line as you would wrap arguments in a
     

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

    -
    class Shape {
    +
    class Shape {
      public:
       virtual void Rotate(double radians) = 0;
     };
    @@ -5264,7 +5310,7 @@ 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:

    -
      ABSL_ATTRIBUTE_NOINLINE void ExpensiveFunction();
    +
      ABSL_ATTRIBUTE_NOINLINE void ExpensiveFunction();
       [[nodiscard]] bool IsOk();
     
    @@ -5275,11 +5321,11 @@ lists like other comma-separated lists.

    For by-reference captures, do not leave a space between the ampersand (&) and the variable name.

    -
    int x = 0;
    +
    int x = 0;
     auto x_plus_n = [&x](int n) -> int { return x + n; }
     

    Short lambdas may be written inline as function arguments.

    -
    absl::flat_hash_set<int> to_remove = {7, 8, 9};
    +
    absl::flat_hash_set<int> to_remove = {7, 8, 9};
     std::vector<int> digits = {3, 9, 1, 8, 4, 7, 1};
     digits.erase(std::remove_if(digits.begin(), digits.end(), [&to_remove](int i) {
                    return to_remove.contains(i);
    @@ -5322,7 +5368,7 @@ minimum number of lines, including placing multiple arguments
     on each line where appropriate.

    Function calls have the following format:

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

    If the arguments do not all fit on one line, they @@ -5330,13 +5376,13 @@ 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 result = DoSomething(averyveryveryverylongargument1,
    +
    bool result = DoSomething(averyveryveryverylongargument1,
                               argument2, argument3);
     

    Arguments may optionally all be placed on subsequent lines with a four space indent:

    -
    if (...) {
    +
    if (...) {
       ...
       ...
       if (...) {
    @@ -5360,13 +5406,13 @@ better addressed with the following techniques.

    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];
    +
    int my_heuristic = scores[x] * y + bases[x];
     bool result = DoSomething(my_heuristic, x, y, z);
     

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

    -
    bool result = DoSomething(scores[x] * y + bases[x],  // Score heuristic.
    +
    bool result = DoSomething(scores[x] * y + bases[x],  // Score heuristic.
                               x, y, z);
     
    @@ -5378,7 +5424,7 @@ which is made more readable rather than a general policy.

    Sometimes arguments form a structure that is important for readability. In those cases, feel free to format the arguments according to that structure:

    -
    // Transform the widget by a 3x3 matrix.
    +
    // Transform the widget by a 3x3 matrix.
     my_widget.Transform(x1, x2, x3,
                         y1, y2, y3,
                         z1, z2, z3);
    @@ -5394,7 +5440,7 @@ variable name), format as if the {} were the
     parentheses of a function call with that name. If there
     is no name, assume a zero-length name.

    -
    // Examples of braced init list on a single line.
    +
    // Examples of braced init list on a single line.
     return {foo, bar};
     functioncall({foo, bar});
     std::pair<int, int> p{foo, bar};
    @@ -5427,7 +5473,7 @@ MyType m = {  // Here, you could also break before {.
     

    At a high level, looping or branching statements consist of the following components:

      -
    • One or more statement keywords (e.g. if, +
    • One or more statement keywords (e.g., if, else, switch, while, do, or for).
    • One condition or iteration specifier, inside @@ -5445,12 +5491,12 @@ For these statements: closing parenthesis or another semicolon.
    • Inside the condition or iteration specifier, do not put a space after the opening parenthesis or before the closing parenthesis.
    • -
    • Put any controlled statements inside blocks (i.e. use curly braces).
    • +
    • Put any controlled statements inside blocks (i.e., use curly braces).
    • Inside the controlled blocks, put one line break immediately after the opening brace, and one line break immediately before the closing brace.
    -
    if (condition) {                   // Good - no spaces inside parentheses, space before brace.
    +
    if (condition) {                   // Good - no spaces inside parentheses, space before brace.
       DoOneThing();                    // Good - two-space indent.
       DoAnotherThing();
     } else if (int a = f(); a != 3) {  // Good - closing brace on new line, else on same line.
    @@ -5539,7 +5585,7 @@ projects require curly braces always.

    braces or not, depending on your preference. If you do include curly braces, they should be placed as shown below.

    -
    switch (var) {
    +
    switch (var) {
       case 0: {  // 2 space indent
         Foo();   // 4 space indent
         break;
    @@ -5553,7 +5599,7 @@ they should be placed as shown below.

    Empty loop bodies should use either an empty pair of braces or continue with no braces, rather than a single semicolon.

    -
    while (condition) {}  // Good - `{}` indicates no logic.
    +
    while (condition) {}  // Good - `{}` indicates no logic.
     while (condition) {
       // Comments are okay, too
     }
    @@ -5563,7 +5609,7 @@ while (condition) continue;  // Good - `continue` indicates no logic.
     
    while (condition);  // Bad - looks like part of `do-while` loop.
     
    -

    Pointer and Reference Expressions

    +

    Pointer and Reference Expressions and Types

    No spaces around period or arrow. Pointer operators do not have trailing spaces.

    @@ -5571,7 +5617,7 @@ have trailing spaces.

    The following are examples of correctly-formatted pointer and reference expressions:

    -
    x = *p;
    +
    x = *p;
     p = &x;
     x = r.y;
     x = r->y;
    @@ -5587,37 +5633,26 @@ x = r->y;
        * or &.
     
     
    -

    When referring to a pointer or reference (variable declarations or definitions, arguments, -return types, template parameters, etc), you may place the space before or after the -asterisk/ampersand. In the trailing-space style, the space is elided in some cases (template -parameters, etc).

    +

    When referring to a pointer or reference (variable declarations or definitions, arguments, return +types, template parameters, etc.), you must not place a space before the asterisk/ampersand. Use a +space to separate the type from the declared name (if present).

    -
    // These are fine, space preceding.
    -char *c;
    -const std::string &str;
    -int *GetPointer();
    -std::vector<char *>
    -
    -// These are fine, space following (or elided).
    +
    // These are fine.
     char* c;
     const std::string& str;
     int* GetPointer();
     std::vector<char*>  // Note no space between '*' and '>'
     
    -

    You should do this consistently within a single -file. -When modifying an existing file, use the style in -that file.

    -

    It is allowed (if unusual) to declare multiple variables in the same declaration, but it is disallowed if any of those have pointer or reference decorations. Such declarations are easily misread.

    -
    // Fine if helpful for readability.
    +
    // Fine if helpful for readability.
     int x, y;
     
    int x, *y;  // Disallowed - no & or * in multiple declaration
    -int* x, *y;  // Disallowed - no & or * in multiple declaration; inconsistent spacing
    +int *x, *y;  // Disallowed - no & or * in multiple declaration
    +int *x;  // Disallowed - & or * must be left of the space
     char * c;  // Bad - spaces on both sides of *
     const std::string & str;  // Bad - spaces on both sides of &
     
    @@ -5631,7 +5666,7 @@ consistent in how you break up the lines.

    In this example, the logical AND operator is always at the end of the lines:

    -
    if (this_one_thing > this_other_thing &&
    +
    if (this_one_thing > this_other_thing &&
         a_third_thing == a_fourth_thing &&
         yet_another && last_one) {
       ...
    @@ -5659,7 +5694,7 @@ expression with parentheses.

    Use parentheses in return expr; only where you would use them in x = expr;.

    -
    return result;                  // No parentheses in the simple case.
    +
    return result;                  // No parentheses in the simple case.
     // Parentheses OK to make a complex expression more readable.
     return (some_long_condition &&
             another_condition);
    @@ -5677,7 +5712,7 @@ return(result);                // return is not a function!
     (), and {}; the following are
     all correct:

    -
    int x = 3;
    +
    int x = 3;
     int x(3);
     int x{3};
     std::string name = "Some Name";
    @@ -5694,7 +5729,7 @@ will call a default constructor if available. To force the
     non-std::initializer_list constructor, use parentheses
     instead of braces.

    -
    std::vector<int> v(100, 1);  // A vector containing 100 items: All 1s.
    +
    std::vector<int> v(100, 1);  // A vector containing 100 items: All 1s.
     std::vector<int> v{100, 1};  // A vector containing 2 items: 100 and 1.
     
    @@ -5702,7 +5737,7 @@ std::vector<int> v{100, 1}; // A vector containing 2 items: 100 and 1. types. This can prevent some types of programming errors.

    -
    int pi(3.14);  // OK -- pi == 3.
    +
    int pi(3.14);  // OK -- pi == 3.
     int pi{3.14};  // Compile error: narrowing conversion.
     
    @@ -5715,7 +5750,7 @@ always be at the beginning of the line.

    of indented code, the directives should start at the beginning of the line.

    -
    // Good - directives at beginning of line
    +
    // Good - directives at beginning of line
       if (lopsided_score) {
     #if DISASTER_PENDING      // Correct -- Starts at beginning of line
         DropEverything();
    @@ -5738,7 +5773,7 @@ beginning of the line.

    Class Format

    -

    Sections in public, protected and +

    Sections in public, protected, and private order, each indented one space.

    The basic format for a class definition (lacking the @@ -5746,7 +5781,7 @@ comments, see Class Comments for a discussion of what comments are needed) is:

    -
    class MyClass : public OtherClass {
    +
    class MyClass : public OtherClass {
      public:      // Note the 1 space indent!
       MyClass();  // Regular 2 space indent.
       explicit MyClass(int var);
    @@ -5800,7 +5835,7 @@ with subsequent lines indented four spaces.

    The acceptable formats for initializer lists are:

    -
    // When everything fits on one line:
    +
    // When everything fits on one line:
     MyClass::MyClass(int var) : some_var_(var) {
       DoSomething();
     }
    @@ -5833,7 +5868,7 @@ MyClass::MyClass(int var)
     

    Namespaces do not add an extra level of indentation. For example, use:

    -
    namespace {
    +
    namespace {
     
     void foo() {  // Correct.  No extra indentation within namespace.
       ...
    @@ -5861,7 +5896,7 @@ trailing whitespace at the end of a line.

    General

    -
    int i = 0;  // Two spaces before end-of-line comments.
    +
    int i = 0;  // Two spaces before end-of-line comments.
     
     void f(bool b) {  // Open braces should always have a space before them.
       ...
    @@ -5882,17 +5917,17 @@ class Foo : public Bar {
     

    Adding trailing whitespace can cause extra work for -others editing the same file, when they merge, as can -removing existing trailing whitespace. So: Don't +others editing the same file when they merge, as can +removing existing trailing whitespace. So, don't introduce trailing whitespace. Remove it if you're already changing that line, or do it in a separate clean-up -operation (preferably when no-one +operation (preferably when no one else is working on the file).

    Loops and Conditionals

    -
    if (b) {          // Space after the keyword in conditions and loops.
    +
    if (b) {          // Space after the keyword in conditions and loops.
     } else {          // Spaces around else.
     }
     while (test) {}   // There is usually no space inside parentheses.
    @@ -5920,7 +5955,7 @@ switch (i) {
     
     

    Operators

    -
    // Assignment operators always have spaces around them.
    +
    // Assignment operators always have spaces around them.
     x = 0;
     
     // Other binary operators usually have spaces around them, but it's
    @@ -5939,7 +5974,7 @@ if (x && !y)
     
     

    Templates and Casts

    -
    // No spaces inside the angle brackets (< and >), before
    +
    // No spaces inside the angle brackets (< and >), before
     // <, or between >( in a cast
     std::vector<std::string> x;
     y = static_cast<char*>(x);
    @@ -5950,43 +5985,16 @@ std::vector<char *> x;
     
     

    Vertical Whitespace

    -

    Minimize use of vertical whitespace.

    +

    Use vertical whitespace sparingly; unnecessary blank lines make it harder to +see overall code structure. Use blank lines only where they aid the reader in +understanding the structure.

    -

    This is more a principle than a rule: don't use blank lines when -you don't have to. In particular, don't put more than one or two blank -lines between functions, resist starting functions with a blank line, -don't end functions with a blank line, and be sparing with your use of -blank lines. A blank line within a block of code serves like a -paragraph break in prose: visually separating two thoughts.

    - -

    The basic principle is: The more code that fits on one screen, the -easier it is to follow and understand the control flow of the -program. Use whitespace purposefully to provide separation in that -flow.

    - -

    Some rules of thumb to help when blank lines may be -useful:

    - -
      -
    • Blank lines at the beginning or end of a function - do not help readability.
    • - -
    • Blank lines inside a chain of if-else blocks may - well help readability.
    • - -
    • A blank line before a comment line usually helps - readability — the introduction of a new comment suggests - the start of a new thought, and the blank line makes it clear - that the comment goes with the following thing instead of the - preceding.
    • - -
    • Blank lines immediately inside a declaration of a namespace or block of - namespaces may help readability by visually separating the load-bearing - content from the (largely non-semantic) organizational wrapper. Especially - when the first declaration inside the namespace(s) is preceded by a comment, - this becomes a special case of the previous rule, helping the comment to - "attach" to the subsequent declaration.
    • -
    +

    Do not add blank lines where indentation already provides clear delineation, +such as at the start or end of a code block. Do use blank lines to separate code +into closely related chunks, analogous to paragraph breaks in prose. Within a +statement or declaration, usually only insert line breaks to stay within +the line length limit, or to attach a comment to only +part of the contents.

    Exceptions to the Rules

    @@ -6100,4 +6108,4 @@ occasionally need to break on Windows:

    - \ No newline at end of file +