From f0314ea7e0a483a10250f46f663d633e69ebd60e Mon Sep 17 00:00:00 2001 From: Victor Costan Date: Sun, 1 Sep 2019 20:42:44 -0700 Subject: [PATCH] Update C++ style guide. --- cppguide.html | 1869 +++++++++++++++---------------------------------- 1 file changed, 572 insertions(+), 1297 deletions(-) diff --git a/cppguide.html b/cppguide.html index 6cf2b13..739912b 100644 --- a/cppguide.html +++ b/cppguide.html @@ -13,7 +13,7 @@
- +

C++ is one of the main development languages used by many of Google's open-source projects. As every C++ @@ -22,8 +22,8 @@ this power brings with it complexity, which in turn can make 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 +describing in detail the dos and don'ts of writing C++ code +. These rules exist to keep the code base manageable while still allowing coders to use C++ language features productively.

@@ -39,13 +39,11 @@ Google conform to the requirements in this guide. - -

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

Goals of the Style Guide

-
+

Why do we have this document?

There are a few core goals that we believe this guide should @@ -125,7 +123,7 @@ trickier language constructs, because any benefits of more complex implementation are multiplied widely by usage, and the cost in understanding the complexity does not need to be paid again when working with new portions of the codebase. When in doubt, waivers to rules of this type -can be sought by asking +can be sought by asking your project leads. This is specifically important for our codebase because code ownership and team membership changes over time: even if everyone that works with some piece of code @@ -157,9 +155,7 @@ same as a license to proceed. Use your judgment, and if you are unsure, please don't hesitate to ask your project leads to get additional input.

-
-

C++ Version

@@ -194,13 +190,10 @@ pitfalls of using header files.

Self-contained Headers

-

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 and be used sparingly.

-
-

All header files should be self-contained. Users and refactoring tools should not have to adhere to special conditions to include the header. Specifically, a header should @@ -229,26 +222,23 @@ their prerequisites. Name such files with the .inc extension. Use sparingly, and prefer self-contained headers when possible.

-
-

The #define Guard

-

All header files should have #define guards to prevent multiple inclusion. The format of the symbol name should be + <PROJECT>_<PATH>_<FILE>_H_.

-
- -
+

To guarantee uniqueness, they should be based on the full path in a project's source tree. For example, the file foo/src/bar/baz.h in project foo should have the following guard:

+
#ifndef FOO_BAR_BAZ_H_
 #define FOO_BAR_BAZ_H_
@@ -260,24 +250,16 @@ guard:

- -
-

Forward Declarations

-
-

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

-
+

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

-
- -
+

A "forward declaration" is a declaration of a class, function, or template without an associated definition.

-
-
+

  • Forward declarations can save compile time, as #includes force the compiler to open @@ -288,9 +270,8 @@ function, or template without an associated definition.

    your code to be recompiled more often, due to unrelated changes in the header.
-
-
+

  • Forward declarations can hide a dependency, allowing user code to skip necessary recompilation when headers @@ -334,11 +315,10 @@ function, or template without an associated definition.

    (e.g. using pointer members instead of object members) can make the code slower and more complex.
  • - -
-
-
+ + +

  • Try to avoid forward declarations of entities defined in another project.
  • @@ -352,33 +332,24 @@ function, or template without an associated definition.

    Please see Names and Order of Includes for rules about when to #include a header.

    -
- -

Inline Functions

-

Define functions inline only when they are small, say, 10 lines or fewer.

-
-
- -
+

You can declare functions in a way that allows the compiler to expand them inline rather than calling them through the usual function call mechanism.

-
-
+

Inlining a function can generate more efficient object code, as long as the inlined function is small. Feel free to inline accessors and mutators, and other short, performance-critical functions.

-
-
+

Overuse of inlining can actually make programs slower. Depending on a function's size, inlining it can cause the code size to increase or decrease. Inlining a very small @@ -386,9 +357,8 @@ accessor function will usually decrease code size while inlining a very large function can dramatically increase code size. On modern processors smaller code usually runs faster due to better use of the instruction cache.

-
-
+

A decent rule of thumb is to not inline a function if it is more than 10 lines long. Beware of destructors, which are often longer than they appear because of @@ -407,23 +377,18 @@ main reason for making a virtual function inline is to place its definition in the class, either for convenience or to document its behavior, e.g., for accessors and mutators.

-
- -

Names and Order of Includes

-
-

Use standard order for readability and to avoid hidden -dependencies: Related header, C library, C++ library, other libraries' -.h, your project's .h.

-
+

Include headers in the following order: Related header, C system headers, +C++ standard library headers, +other libraries' headers, your project's +headers.

-

All of a project's header files should be listed as descendants of the project's source -directory without use of UNIX directory shortcuts +directory without use of UNIX directory aliases . (the current directory) or .. (the parent directory). For example, @@ -444,23 +409,29 @@ as follows:

  • A blank line
  • -
  • C system files.
  • - -
  • C++ system files.
  • +
  • C system headers (more precisely: headers in angle brackets with the + .h extension), e.g. <unistd.h>, + <stdlib.h>.
  • A blank line
  • -
  • Other libraries' .h - files.
  • +
  • C++ standard library headers (without file extension), e.g. + <algorithm>, <cstddef>.
  • + +
  • A blank line
  • + +
    +
  • Other libraries' .h files.
  • +
  • Your project's .h files.
  • -

    Note that any adjacent blank lines should be collapsed.

    +

    Separate each non-empty group with one blank line.

    -

    With the preferred ordering, if +

    With the preferred ordering, if the related header dir2/foo2.h omits any necessary includes, the build of dir/foo.cc or dir/foo_test.cc will break. @@ -476,9 +447,9 @@ directories too.

    -

    Note that the C compatibility headers such as stddef.h +

    Note that the C headers such as stddef.h are essentially interchangeable with their C++ counterparts -(cstddef) +(cstddef). Either style is acceptable, but prefer consistency with existing code.

    Within each section the includes should be ordered @@ -491,21 +462,19 @@ declaration. If you rely on symbols from bar.h, don't count on the fact that you included foo.h which (currently) includes bar.h: include bar.h yourself, unless foo.h explicitly demonstrates its intent -to provide you the symbols of bar.h. However, any -includes present in the related header do not need to be included -again in the related cc (i.e., foo.cc can -rely on foo.h's includes).

    +to provide you the symbols of bar.h.

    For example, the includes in google-awesome-project/src/foo/internal/fooserver.cc might look like this:

    -
    #include "foo/server/fooserver.h"
     
     #include <sys/types.h>
     #include <unistd.h>
    +
    +#include <string>
     #include <vector>
     
     #include "base/basictypes.h"
    @@ -513,7 +482,9 @@ might look like this:

    #include "foo/server/bar.h"
    -

    Sometimes, system-specific code needs +

    Exception:

    + +

    Sometimes, system-specific code needs conditional includes. Such code can put conditional includes after other includes. Of course, keep your system-specific code small and localized. Example:

    @@ -527,13 +498,10 @@ system-specific code small and localized. Example:

    #endif // LANG_CXX11 -
    -

    Scoping

    Namespaces

    -

    With few exceptions, place code in a namespace. Namespaces should have unique names based on the project name, and possibly its path. Do not use using-directives (e.g. @@ -541,17 +509,13 @@ its path. Do not use using-directives (e.g. inline namespaces. For unnamed namespaces, see Unnamed Namespaces and Static Variables. -

    -
    - -
    +

    Namespaces subdivide the global scope into distinct, named scopes, and so are useful for preventing name collisions in the global scope.

    -
    -
    +

    Namespaces provide a method for preventing name conflicts in large programs while allowing most code to use reasonably @@ -569,7 +533,7 @@ can continue to refer to Foo without the prefix.

    the enclosing scope. Consider the following snippet, for example:

    -
    namespace outer {
    +
    namespace outer {
     inline namespace inner {
       void foo();
     }  // namespace inner
    @@ -580,9 +544,8 @@ inline namespace inner {
     outer::foo() are interchangeable. Inline
     namespaces are primarily intended for ABI compatibility
     across versions.

    -
    -
    +

    Namespaces can be confusing, because they complicate the mechanics of figuring out what definition a name refers @@ -596,9 +559,8 @@ some larger versioning policy.

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

    -
    -
    +

    Namespaces should be used as follows:

    @@ -608,7 +570,7 @@ namespaces, this can add a lot of clutter.

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

    @@ -643,11 +605,11 @@ void MyClass::Foo() {
    #include "a.h"
     
    -DEFINE_FLAG(bool, someflag, false, "dummy flag");
    +ABSL_FLAG(bool, someflag, false, "dummy flag");
     
     namespace mynamespace {
     
    -using ::foo::bar;
    +using ::foo::Bar;
     
     ...code for mynamespace...    // Code goes against the left margin.
     
    @@ -659,7 +621,8 @@ using ::foo::bar;
       message code in a namespace, use the
       package specifier in the
       .proto file. See
    -  
    +
    +
       
       Protocol Buffer Packages
       for details.
  • @@ -705,30 +668,23 @@ inline void my_inline_function() {
  • Do not use inline namespaces.
  • -
    -

    Unnamed Namespaces and Static Variables

    -

    When definitions in a .cc file do not need to be referenced outside that file, place them in an unnamed namespace or declare them static. Do not use either of these constructs in .h files. -

    -
    - -
    +

    All declarations can be given internal linkage by placing them in unnamed namespaces. Functions and variables can also be given internal linkage by declaring them static. This means that anything you're declaring can't be accessed from another file. If a different file declares something with the same name, then the two entities are completely independent.

    -
    -
    +

    Use of internal linkage in .cc files is encouraged for all code that does not need to be referenced elsewhere. @@ -741,33 +697,26 @@ Do not use internal linkage in .h files.

    ... } // namespace -
    -

    Nonmember, Static Member, and Global Functions

    -

    Prefer placing nonmember functions in a namespace; use completely global functions rarely. Do not use a class simply to group static functions. Static methods of a class should generally be closely related to instances of the class or the class's static data.

    -
    -
    -
    -

    Nonmember and static member functions can be useful in - some situations. Putting nonmember functions in a - namespace avoids polluting the global namespace.

    -
    +

    +

    Nonmember and static member functions can be useful in +some situations. Putting nonmember functions in a +namespace avoids polluting the global namespace.

    -
    +

    Nonmember and static member functions may make more sense as members of a new class, especially if they access external resources or have significant dependencies.

    -
    -
    +

    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. @@ -781,18 +730,11 @@ common prefix, and such grouping is usually unnecessary anyway.

    needed in its .cc file, use internal linkage to limit its scope.

    -
    - -

    Local Variables

    -

    Place a function's variables in the narrowest scope possible, and initialize variables in the declaration.

    -
    - -

    C++ allows you to declare variables anywhere in a function. We encourage you to declare them in as local a @@ -846,11 +788,8 @@ for (int i = 0; i < 1000000; ++i) { } -

    -

    Static and Global Variables

    -

    Objects with static storage duration are forbidden unless they are @@ -866,11 +805,8 @@ for details.

    As a rule of thumb: a global variable satisfies these requirements if its declaration, considered in isolation, could be constexpr.

    -
    -
    - -
    +

    Every object has a storage duration, which correlates with its lifetime. Objects with static storage duration live from the point of their initialization until the end of the program. Such objects appear as variables at @@ -891,16 +827,14 @@ initialization always happens to objects with static storage duration (initializing the object either to a given constant or to a representation consisting of all bytes set to zero), whereas dynamic initialization happens after that, if required.

    -
    -
    +

    Global and static variables are very useful for a large number of applications: named constants, auxiliary data structures internal to some translation unit, command-line flags, logging, registration mechanisms, background infrastructure, etc.

    -
    -
    +

    Global and static variables that use dynamic initialization or have non-trivial destructors create complexity that can easily lead to hard-to-find bugs. Dynamic initialization is not ordered across translation units, and @@ -911,9 +845,8 @@ an object to be accessed before its lifetime has begun (or after its lifetime has ended). Moreover, when a program starts threads that are not joined at exit, those threads may attempt to access objects after their lifetime has ended if their destructor has already run.

    -
    -
    +

    Decision on destruction

    When destructors are trivial, their execution is not subject to ordering at @@ -935,11 +868,11 @@ void foo() { // allowed: constexpr guarantees trivial destructor constexpr std::array<int, 3> kArray = {{1, 2, 3}};

    // bad: non-trivial destructor
    -const string kFoo = "foo";
    +const std::string kFoo = "foo";
     
     // bad for the same reason, even though kBar is a reference (the
     // rule also applies to lifetime-extended temporary objects)
    -const string& kBar = StrCat("a", "b", "c");
    +const std::string& kBar = StrCat("a", "b", "c");
     
     void bar() {
       // bad: non-trivial destructor
    @@ -959,7 +892,8 @@ evaluation of the initializer:

    int n = 5;    // fine
     int m = f();  // ? (depends on f)
     Foo x;        // ? (depends on Foo::Foo)
    -Bar y = g();  // ? (depends on g and on Bar::Bar)
    +Bar y = g(); // ? (depends on g and on Bar::Bar) +

    All but the first statement expose us to indeterminate initialization ordering.

    @@ -979,6 +913,7 @@ Foo a[] = { Foo(1), Foo(2), Foo(3) }; // fine static storage duration variables should be marked with constexpr or where possible the + ABSL_CONST_INIT attribute. Any non-local static storage @@ -1008,7 +943,6 @@ does not make an observable difference. For example:

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

    -

    Common patterns

    @@ -1024,10 +958,15 @@ does not make an observable difference. For example:

    trivial types, e.g. an array of arrays of ints (for a "map from int to int"), or an array of pairs (e.g. pairs of int and const char*). For small collections, linear search is entirely sufficient - (and efficient, due to memory locality). If necessary, keep the collection in - sorted order and use a binary search algorithm. If you do really prefer a - dynamic container from the standard library, consider using a function-local - static pointer, as described below. + (and efficient, due to memory locality); consider using the facilities from + + absl/algorithm/container.h + + + for the standard operations. If necessary, keep the collection in sorted + order and use a binary search algorithm. If you do really prefer a dynamic + container from the standard library, consider using a function-local static + pointer, as described below.
  • Smart pointers (unique_ptr, shared_ptr): smart pointers execute cleanup during destruction and are therefore forbidden. Consider whether your use case fits into one of the other patterns described @@ -1037,30 +976,23 @@ does not make an observable difference. For example:

    a type that you need to define yourself, give the type a trivial destructor and a constexpr constructor.
  • If all else fails, you can create an object dynamically and never delete - it by binding the pointer to a function-local static pointer variable: - static const auto* const impl = new T(args...); (If the - initialization is more complex, it can be moved into a function or lambda - expression.)
  • + it by using a function-local static pointer or reference (e.g. static + const auto& impl = *new T(args...);). -
    -

    thread_local Variables

    -

    thread_local variables that aren't declared inside a function must be initialized with a true compile-time constant, and this must be enforced by using the + ABSL_CONST_INIT attribute. Prefer thread_local over other ways of defining thread-local data.

    -
    -
    - -
    +

    Starting with C++11, variables can be declared with the thread_local specifier:

    thread_local Foo foo = ...;
    @@ -1083,9 +1015,8 @@ initialization-order issues as static variables (and more besides).

    thread_local variable instances are destroyed when their thread terminates, so they do not have the destruction-order issues of static variables.

    -
    -
    +

    • Thread-local data is inherently safe from races (because only one thread can ordinarily access it), which makes thread_local useful for @@ -1093,9 +1024,8 @@ variables.

    • thread_local is the only standard-supported way of creating thread-local data.
    -
    -
    +

    • Accessing a thread_local variable may trigger execution of an unpredictable and uncontrollable amount of other code.
    • @@ -1109,9 +1039,8 @@ variables.

    • thread_local may not be as efficient as certain compiler intrinsics.
    -
    -
    +

    thread_local variables inside a function have no safety concerns, so they can be used without restriction. Note that you can use a function-scope thread_local to simulate a class- or @@ -1124,25 +1053,21 @@ variables.

    } -

    thread_local variables at class or namespace scope must be - initialized with a true compile-time constant (i.e. they must have no - dynamic initialization). To enforce this, - thread_local variables at class or namespace scope must be - annotated with - - - ABSL_CONST_INIT - (or constexpr, but that should be rare):

    +

    thread_local variables at class or namespace scope must be +initialized with a true compile-time constant (i.e. they must have no +dynamic initialization). To enforce this, thread_local variables +at class or namespace scope must be annotated with + + + +ABSL_CONST_INIT +(or constexpr, but that should be rare):

    ABSL_CONST_INIT thread_local Foo foo = ...;
     
    -

    thread_local should be preferred over other mechanisms for - defining thread-local data.

    -
    - -
    - +

    thread_local should be preferred over other mechanisms for +defining thread-local data.

    Classes

    @@ -1152,19 +1077,14 @@ don'ts you should follow when writing a class.

    Doing Work in Constructors

    -

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

    -
    -
    - -
    +

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

    -
    -
    +

    • No need to worry about whether the class has been initialized or not.
    • @@ -1174,9 +1094,7 @@ of the constructor.

      or algorithms.
    -
    - -
    +

    • If the work calls virtual functions, these calls will not get dispatched to the subclass @@ -1197,40 +1115,28 @@ of the constructor.

      is done in the constructor cannot easily be handed off to, for example, another thread.
    -
    - -
    +

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

    -
    - -

    Implicit Conversions

    -

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

    -
    -
    - -
    +

    Implicit conversions allow an object of one type (called the source type) to be used where a different type (called the destination @@ -1263,9 +1169,8 @@ void Func(Foo f); This kind of code isn't technically an implicit conversion, but the language treats it as one as far as explicit is concerned. -

    -
    +

    • Implicit conversions can make a type more usable and expressive by eliminating the need to explicitly name a type @@ -1273,14 +1178,13 @@ language treats it as one as far as explicit is concerned.
    • Implicit conversions can be a simpler alternative to overloading, such as when a single function with a string_view parameter takes the - place of separate overloads for string and + place of separate overloads for std::string and const char*.
    • List initialization syntax is a concise and expressive way of initializing objects.
    -
    -
    +

    • Implicit conversions can hide type-mismatch bugs, where the destination type does not match the user's expectation, or @@ -1306,9 +1210,8 @@ language treats it as one as far as explicit is concerned. the destination type is implicit, particularly if the list has only a single element.
    -
    -
    +

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

    @@ -1325,21 +1228,15 @@ may omit explicit. Constructors that take a single std::initializer_list parameter should also omit explicit, in order to support copy-initialization (e.g. MyType m = {1, 2};).

    -
    - -

    Copyable and Movable Types

    -
    -

    A class's public API should make explicit whether the class is copyable, + +

    A class's public API must make clear whether the class is copyable, move-only, or neither copyable nor movable. Support copying and/or moving if these operations are clear and meaningful for your type.

    -
    -
    - -
    +

    A movable type is one that can be initialized and assigned from temporaries.

    @@ -1349,9 +1246,9 @@ stipulation that the value of the source does not change. std::unique_ptr<int> is an example of a movable but not copyable type (since the value of the source std::unique_ptr<int> must be modified during assignment to -the destination). int and string are examples of +the destination). int and std::string are examples of movable types that are also copyable. (For int, the move and copy -operations are the same; for string, there exists a move operation +operations are the same; for std::string, there exists a move operation that is less expensive than a copy.)

    For user-defined types, the copy behavior is defined by the copy @@ -1361,9 +1258,8 @@ copy constructor and the copy-assignment operator otherwise.

    The copy/move constructors can be implicitly invoked by the compiler in some situations, e.g. when passing objects by value.

    -
    -
    +

    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, @@ -1390,9 +1286,8 @@ copy elision.

    Move operations allow the implicit and efficient transfer of resources out of rvalue objects. This allows a plainer coding style in some cases.

    -
    -
    +

    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), @@ -1408,11 +1303,10 @@ resulting bugs can be confusing and difficult to diagnose.

    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.

    -
    -
    +

    -

    Every class's public interface should make explicit which copy and move +

    Every class's public interface must make clear which copy and move operations the class supports. This should usually take the form of explicitly declaring and/or deleting the appropriate operations in the public section of the declaration.

    @@ -1426,16 +1320,16 @@ must also provide the corresponding constructor.

    class Copyable {
      public:
    -  Copyable(const Copyable& rhs) = default;
    -  Copyable& operator=(const Copyable& rhs) = default;
    +  Copyable(const Copyable& other) = default;
    +  Copyable& operator=(const Copyable& other) = default;
     
       // The implicit move operations are suppressed by the declarations above.
     };
     
     class MoveOnly {
      public:
    -  MoveOnly(MoveOnly&& rhs);
    -  MoveOnly& operator=(MoveOnly&& rhs);
    +  MoveOnly(MoveOnly&& other);
    +  MoveOnly& operator=(MoveOnly&& other);
     
       // The copy operations are implicitly deleted, but you can
       // spell that out explicitly if you want:
    @@ -1458,16 +1352,19 @@ class NotCopyableOrMovable {
     };
     
    -

    These declarations/deletions can be omitted only if they are obvious: for -example, if a base class isn't copyable or movable, derived classes naturally -won't be either. Similarly, a struct's -copyability/movability is normally determined by the copyability/movability -of its data members (this does not apply to classes because in Google code -their data members are not public). Note that if you explicitly declare or -delete any of the copy/move operations, the others are not obvious, and so -this paragraph does not apply (in particular, the rules in this section -that apply to "classes" also apply to structs that declare or delete any -copy/move operations).

    +

    These declarations/deletions can be omitted only if they are obvious: +

      +
    • If the class has no private section, like a + struct or an interface-only base class, + then the copyability/movability can be determined by the + copyability/movability of any public data members. +
    • If a base class clearly isn't copyable or movable, derived classes + naturally won't be either. An interface-only base class that leaves these + operations implicit is not sufficient to make concrete subclasses clear. +
    • Note that if you explicitly declare or delete either the constructor or + assignment operation for copy, the other copy operation is not obvious and + must be declared or deleted. Likewise for move operations. +

    A type should not be copyable/movable if the meaning of copying/moving is unclear to a casual user, or if it incurs unexpected @@ -1489,17 +1386,10 @@ can use to implement it.

    -
    -
    -

    Structs vs. Classes

    -

    Use a struct only for passive objects that carry data; everything else is a class.

    -
    - -

    The struct and class keywords behave almost identically in C++. We add our own @@ -1507,40 +1397,58 @@ semantic meanings to each keyword, so you should use the appropriate keyword for the data-type you're defining.

    -

    structs should be used for passive -objects that carry data, and may have associated -constants, but lack any functionality other than -access/setting the data members. The accessing/setting of -fields is done by directly accessing the fields rather -than through method invocations. Methods should not -provide behavior but should only be used to set up the -data members, e.g., constructor, destructor, -Initialize(), Reset(), -Validate().

    +

    structs should be used for passive objects that carry +data, and may have associated constants, but lack any functionality +other than access/setting the data members. All fields must be public, +and accessed directly rather than through getter/setter methods. The +struct must not have invariants that imply relationships between +different fields, since direct user access to those fields may break +those invariants. Methods should not provide behavior but should only +be used to set up the data members, e.g., constructor, destructor, +Initialize(), Reset().

    -

    If more functionality is required, a +

    If more functionality or invariants are required, a class is more appropriate. If in doubt, make it a class.

    For consistency with STL, you can use struct instead of class for -functors and traits.

    +stateless types, such as traits, +template metafunctions, +and some functors.

    Note that member variables in structs and classes have different naming rules.

    -
    +

    Structs vs. Pairs and Tuples

    + +

    Prefer to use a struct instead of a pair or a +tuple whenever the elements can have meaningful names.

    + +

    + While using pairs and tuples can avoid the need to define a custom type, + potentially saving work when writing code, a meaningful field + name will almost always be much clearer when reading code than + .first, .second, or std::get<X>. + While C++14's introduction of std::get<Type> to access a + tuple element by type rather than index (when the type is unique) can + sometimes partially mitigate this, a field name is usually substantially + clearer and more informative than a type. +

    + +

    + Pairs and tuples may be appropriate in generic code where there are not + specific meanings for the elements of the pair or tuple. Their use may + also be required in order to interoperate with existing code or APIs. +

    Inheritance

    -

    Composition is often more appropriate than inheritance. When using inheritance, make it public.

    -
    -
    -
    +

    When a sub-class inherits from a base class, it includes the definitions of all the data and operations that the base class @@ -1548,9 +1456,8 @@ defines. "Interface inheritance" is inheritance from a pure abstract base class (one with no state or defined methods); all other inheritance is "implementation inheritance".

    -
    -
    +

    Implementation inheritance reduces code size by re-using the base class code as it specializes an existing type. Because inheritance is a compile-time declaration, you @@ -1560,9 +1467,8 @@ programmatically enforce that a class expose a particular API. Again, the compiler can detect errors, in this case, when a class does not define a necessary method of the API.

    -
    -
    +

    For implementation inheritance, because the code implementing a sub-class is spread between the base and the sub-class, it can be more difficult to understand an @@ -1577,9 +1483,8 @@ inheritance can often be greater than the performance drop from ordinary to virtual dispatch), and because it risks leading to "diamond" inheritance patterns, which are prone to ambiguity, confusion, and outright bugs.

    -
    -
    +

    All inheritance should be public. If you want to do private inheritance, you should be including @@ -1610,21 +1515,14 @@ present, the reader has to check all ancestors of the class in question to determine if the function or destructor is virtual or not.

    -

    Multiple inheritance is permitted, but multiple implementation +

    Multiple inheritance is permitted, but multiple implementation inheritance is strongly discouraged.

    -
    - -

    Operator Overloading

    -
    -

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

    -
    +

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

    -
    - -
    +

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

    -
    -
    +

    Operator overloading can make code more concise and intuitive by enabling user-defined types to behave the same as built-in types. Overloaded operators are the idiomatic names @@ -1647,9 +1544,8 @@ those names.

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

    -
    -
    +

    • Providing a correct, consistent, and unsurprising set of operator overloads requires some care, and failure @@ -1691,13 +1587,23 @@ creating objects of user-defined types.

      in undefined behavior, which can manifest as subtle run-time bugs.
    • -
    • User-defined literals allow the creation of new +
    • User-defined literals (UDLs) allow the creation of new syntactic forms that are unfamiliar even to experienced C++ - programmers.
    • -
    -
    + programmers, such as "Hello World"sv as a + shorthand for std::string_view("Hello World"). + Existing notations are clearer, though less terse. -
    +
  • Because they can't be namespace-qualified, uses of UDLs also require + use of either using-directives (which we ban) or + using-declarations (which we ban in header files except + when the imported names are part of the interface exposed by the header + file in question). Given that header files would have to avoid UDL + suffixes, we prefer to avoid having conventions for literals differ + between header files and source files. +
  • + + +

    Define overloaded operators only if their meaning is obvious, unsurprising, and consistent with the corresponding built-in operators. For example, use | as a @@ -1737,7 +1643,8 @@ use a custom comparator rather than overloading

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

    +literals. Do not use any such literals provided by others +(including the standard library).

    Type conversion operators are covered in the section on implicit conversions. @@ -1747,19 +1654,12 @@ The = operator is covered in the section on section on streams. See also the rules on function overloading, which apply to operator overloading as well.

    -
    - -

    Access Control

    -

    Make classes' data members private, unless they are -static const (and follow the -naming convention for constants).

    -
    - -
    +constants. This simplifies reasoning about invariants, at the cost +of some easy boilerplate in the form of accessors (usually const) if necessary.

    For technical reasons, we allow data members of a test fixture class in a .cc file to @@ -1769,16 +1669,10 @@ be protected when using Google Test).

    -
    -

    Declaration Order

    -

    Group similar declarations together, placing public parts earlier.

    -
    - -

    A class definition should usually start with a public: section, followed by @@ -1798,26 +1692,18 @@ performance-critical, and very short, methods may be defined inline. See Inline Functions for more details.

    -
    -

    Functions

    Output Parameters

    -
    -

    Prefer using return values rather than output parameters. -If output-only parameters are used they should appear after -input parameters.

    -
    - -

    The output of a C++ function is naturally provided via a return value and sometimes via output parameters.

    -

    Prefer using return values instead of output parameters -since they improve readability and oftentimes provide the same -or better performance.

    +

    Prefer using return values over output parameters: they +improve readability, and often provide the same or better +performance. If output-only parameters are used, +they should appear after input parameters.

    Parameters are either input to the function, output from the function, or both. Input parameters are usually values or @@ -1835,15 +1721,10 @@ both input and output (often classes/structs) muddy the waters, and, as always, consistency with related functions may require you to bend the rule.

    -
    -

    Write Short Functions

    -

    Prefer small and focused functions.

    -
    -

    We recognize that long functions are sometimes appropriate, so no hard limit is placed on functions length. If a function exceeds about 40 lines, think about @@ -1854,10 +1735,11 @@ of the program.

    someone modifying it in a few months may add new behavior. This could result in bugs that are hard to find. Keeping your functions short and simple makes it -easier for other people to read and modify your code.

    +easier for other people to read and modify your code. +Small functions are also easier to test.

    You could find long and complicated functions when -working with +working with some code. Do not be intimidated by modifying existing code: if working with such a function proves to be difficult, you find that @@ -1865,43 +1747,34 @@ errors are hard to debug, or you want to use a piece of it in several different contexts, consider breaking up the function into smaller and more manageable pieces.

    -
    -

    Reference Arguments

    -

    All parameters passed by lvalue reference must be labeled const.

    -
    -
    - -
    +

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

    -
    -
    +

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

    -
    -
    +

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

    -
    -
    +

    Within function parameter lists all references must be const:

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

    In fact it is a very strong convention in Google code @@ -1932,58 +1805,47 @@ T* rather than const T&, do so for a concrete reason; otherwise it will likely confuse readers by making them look for an explanation that doesn't exist.

    -
    - -

    Function Overloading

    -

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

    -
    -
    - -
    +

    You may write a function that takes a const -string& and overload it with another that +std::string& and overload it with another that takes const char*. However, in this case consider std::string_view instead.

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

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

    Overloading based on const or ref qualification may make utility code more usable, more efficient, or both. - (See TotW 148 for more.)

    -
    -
    +

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

    -
    -
    +

    You may overload a function when there are no semantic differences between variants. These overloads may vary in types, qualifiers, or argument count. However, a reader of such a call must not need to know @@ -1991,23 +1853,16 @@ 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.

    -
    - -

    Default Arguments

    -

    Default arguments are allowed on non-virtual functions when the default is guaranteed to always have the same value. Follow the same restrictions as for function overloading, and prefer overloaded functions if the readability gained with default arguments doesn't outweigh the downsides below.

    -
    -
    - -
    +

    Often you have a function that uses default values, but occasionally you want to override the defaults. Default parameters allow an easy way to do this without having to @@ -2016,9 +1871,8 @@ to overloading the function, default arguments have a cleaner syntax, with less boilerplate and a clearer distinction between 'required' and 'optional' arguments.

    -
    -
    +

    Defaulted arguments are another way to achieve the semantics of overloaded functions, so all the reasons not to overload functions apply.

    @@ -2037,9 +1891,8 @@ of varying at each call.

    default arguments, since the function signature often doesn't match the call signature. Adding function overloads avoids these problems.

    -
    -
    +

    Default arguments are banned on virtual functions, where they don't work properly, and in cases where the specified default might not evaluate to the same value depending on @@ -2050,17 +1903,13 @@ f(int n = counter++);.)

    readability of their function declarations enough to overcome the downsides above, so they are allowed. When in doubt, use overloads.

    -
    - -

    Trailing Return Type Syntax

    -
    +

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

    -
    -
    +

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

    int foo(int x);
    @@ -2075,10 +1924,8 @@ doubt, use overloads.

    make a difference for a simple case like int but it matters for more complicated cases, like types declared in class scope or types written in terms of the function parameters.

    -
    -
    -
    +

    Trailing return types are the only way to explicitly specify the return type of a lambda expression. In some cases the compiler is able to deduce a lambda's return type, @@ -2096,9 +1943,8 @@ doubt, use overloads.

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

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

    @@ -2106,9 +1952,8 @@ doubt, use overloads.

    declarations that aren't going to get changed to use the new syntax, so the realistic choices are using the old syntax only or using a mixture of the two. Using a single version is better for uniformity of style.

    -
    -
    +

    In most cases, continue to use the older style of function declaration where the return type goes before the function name. Use the new trailing-return-type form only in cases where it's @@ -2118,30 +1963,26 @@ doubt, use overloads.

    issue in fairly complicated template code, which is discouraged in most cases.

    -
    -

    Google-Specific Magic

    +

    There are various tricks and utilities that we use to make C++ code more robust, and various ways we use C++ that may differ from what you see elsewhere.

    +
    + -

    Ownership and Smart Pointers

    -

    Prefer to have single, fixed owners for dynamically allocated objects. Prefer to transfer ownership with smart pointers.

    -
    -
    - -
    +

    "Ownership" is a bookkeeping technique for managing dynamically allocated memory (and other resources). The owner of a dynamically allocated object is an object or @@ -2171,9 +2012,8 @@ a dynamically allocated object. std::shared_ptrs can be copied; ownership of the object is shared among all copies, and the object is deleted when the last std::shared_ptr is destroyed.

    -
    -
    +

    • It's virtually impossible to manage dynamically allocated memory without some sort of ownership @@ -2198,9 +2038,8 @@ all copies, and the object is deleted when the last
    • For const objects, shared ownership can be a simple and efficient alternative to deep copying.
    -
    -
    +

    • Ownership must be represented and transferred via pointers (whether smart or plain). Pointer semantics @@ -2237,9 +2076,8 @@ all copies, and the object is deleted when the last
    • Smart pointers are not perfect substitutes for plain pointers.
    -
    -
    +

    If dynamic allocation is necessary, prefer to keep ownership with the code that allocated it. If other code needs access to the object, consider passing it a copy, @@ -2264,17 +2102,10 @@ do use shared ownership, prefer to use

    Never use std::auto_ptr. Instead, use std::unique_ptr.

    -
    - -

    cpplint

    -

    Use cpplint.py to detect style errors.

    -
    - -

    cpplint.py is a tool that reads a source file and identifies many @@ -2286,22 +2117,21 @@ NOLINT at the end of the line or +

    Some projects have instructions on how to run cpplint.py from their project tools. If the project you are contributing to does not, you can download cpplint.py separately.

    +
    -
    -

    Other C++ Features

    Rvalue References

    -

    Use rvalue references to:

    • Define move constructors and move assignment operators.
    • @@ -2315,30 +2145,26 @@ you can download
    • Support 'perfect forwarding' in generic code.
    -
    -
    - -
    +

    Rvalue references are a type of reference that can only bind to temporary objects. The syntax is similar to traditional reference -syntax. For example, void f(string&& +syntax. For example, void f(std::string&& s); declares a function whose argument is an -rvalue reference to a string.

    +rvalue reference to a std::string.

    When the token '&&' is applied to an unqualified template argument in a function parameter, special template argument deduction rules apply. Such a reference is called forwarding reference.

    -
    -
    +

    • Defining a move constructor (a constructor taking an rvalue reference to the class type) makes it possible to move a value instead of copying it. If - v1 is a std::vector<string>, + v1 is a std::vector<std::string>, for example, then auto v2(std::move(v1)) will probably just result in some simple pointer manipulation instead of copying a large amount of data. @@ -2362,49 +2188,42 @@ rules apply. Such a reference is called forwarding reference.

      arguments are temporary objects and/or const. This is called 'perfect forwarding'.
    -
    -
    +

      -
    • Rvalue references are not yet widely - understood. Rules like automatic synthesis of move constructors and reference - collapsing (the latter refers to the special rules that apply to a T&& - parameter in a function template) are somewhat obscure.
    • +
    • Rvalue references are not yet widely understood. Rules like reference + collapsing and the special deduction rule for forwarding references + are somewhat obscure.
    • Rvalue references are often misused. Using rvalue references is counter-intuitive in signatures where the argument is expected to have a valid specified state after the function call, or where no move operation is performed.
    -
    -
    -

    You may use rvalue references to define move constructors and move - assignment operators (as described in Copyable and Movable Types). See the C++ Primer for more information about - move semantics and std::move.

    +

    +

    You may use rvalue references to define move constructors and move +assignment operators (as described in +Copyable and Movable Types). See the +C++ Primer for more information about +move semantics and std::move.

    -

    You may use rvalue references to define pairs of overloads, one taking - Foo&& and the other taking const Foo&. Usually the preferred - solution is just to pass by value, but an overloaded pair of functions - sometimes yields better performance and is sometimes necessary in generic code - that needs to support a wide variety of types. As always: if you're writing - more complicated code for the sake of performance, make sure you have evidence - that it actually helps.

    +

    You may use rvalue references to define pairs of overloads, one taking +Foo&& and the other taking const Foo&. +Usually the preferred solution is just to pass by value, but an overloaded pair +of functions sometimes yields better performance and is sometimes necessary in +generic code that needs to support a wide variety of types. As always: if +you're writing more complicated code for the sake of performance, make sure you +have evidence that it actually helps.

    -

    You may use forwarding references in conjunction with std::forward, - to support perfect forwarding.

    -
    - -
    +

    You may use forwarding references in conjunction with +std::forward, +to support perfect forwarding.

    Friends

    -

    We allow use of friend classes and functions, within reason.

    -
    - -

    Friends should usually be defined in the same file so that the reader does not have to look in another file to @@ -2423,29 +2242,25 @@ other class access to it. However, most classes should interact with other classes solely through their public members.

    -
    -

    Exceptions

    -

    We do not use C++ exceptions.

    -
    -
    - -
    +

    • Exceptions allow higher levels of an application to decide how to handle "can't happen" failures in deeply nested functions, without the obscuring and error-prone bookkeeping of error codes.
    • - + +
    • Exceptions are used by most other modern languages. Using them in C++ would make it more consistent with Python, Java, and the C++ that others are familiar with.
    • +
    • Some third-party C++ libraries use exceptions, and turning them off internally makes it harder to @@ -2459,9 +2274,8 @@ members.

    • Exceptions are really handy in testing frameworks.
    -
    -
    +

    • When you add a throw statement to an existing function, you must examine all of its @@ -2505,9 +2319,8 @@ members.

      to be thrown. We would need to make the style guide even longer to document these restrictions!
    -
    -
    +

    On their face, the benefits of using exceptions outweigh the costs, especially in new projects. However, for existing code, the introduction of exceptions has @@ -2544,18 +2357,11 @@ features added in C++11, such as

    There is an exception to this rule (no pun intended) for Windows code.

    -
    - -
    -

    noexcept

    -

    Specify noexcept when it is useful and correct.

    -
    -
    -
    +

    The noexcept specifier is used to specify whether a function will throw exceptions or not. If an exception escapes from a function marked noexcept, the program @@ -2565,9 +2371,7 @@ crashes via std::terminate.

    check that returns true if an expression is declared to not throw any exceptions.

    -
    - -
    +

    • Specifying move constructors as noexcept improves performance in some cases, e.g. @@ -2582,12 +2386,11 @@ throw any exceptions.

      that no exceptions can be thrown due to a noexcept specifier.
    -
    -
    +

    • - + In projects following this guide that have exceptions disabled it is hard to ensure that noexcept @@ -2598,9 +2401,8 @@ throw any exceptions.

      because it eliminates a guarantee that callers may be relying on, in ways that are hard to detect.
    -
    -
    +

    You may use noexcept when it is useful for performance if it accurately reflects the intended semantics of your function, i.e. that if an exception is somehow thrown @@ -2609,7 +2411,7 @@ You can assume that noexcept on move constructors has a meaningful performance benefit. If you think there is significant performance benefit from specifying noexcept on some other function, please discuss it -with +with your project leads.

    Prefer unconditional noexcept if exceptions are @@ -2637,39 +2439,18 @@ simply document that your component doesn’t support hash functions throwing and make it unconditionally noexcept.

    -
    - -
    -

    Run-Time Type Information (RTTI)

    -

    Avoid using Run Time Type Information (RTTI).

    -
    -
    - -
    +

    RTTI allows a programmer to query the C++ class of an object at run time. This is done by use of typeid or dynamic_cast.

    -
    -
    -

    Querying the type of an object at run-time frequently -means a design problem. Needing to know the type of an -object at runtime is often an indication that the design -of your class hierarchy is flawed.

    - -

    Undisciplined use of RTTI makes code hard to maintain. -It can lead to type-based decision trees or switch -statements scattered throughout the code, all of which -must be examined when making further changes.

    -
    - -
    +

    The standard alternatives to RTTI (described below) require modification or redesign of the class hierarchy in question. Sometimes such modifications are infeasible @@ -2693,9 +2474,19 @@ bool Derived::Equal(Base* other) { ... } -

    -
    +

    +

    Querying the type of an object at run-time frequently +means a design problem. Needing to know the type of an +object at runtime is often an indication that the design +of your class hierarchy is flawed.

    + +

    Undisciplined use of RTTI makes code hard to maintain. +It can lead to type-based decision trees or switch +statements scattered throughout the code, all of which +must be examined when making further changes.

    + +

    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 @@ -2745,13 +2536,9 @@ find and modify all the affected code segments.

    arguments against RTTI apply just as much to workarounds like class hierarchies with type tags. Moreover, workarounds disguise your true intent.

    -
    - -

    Casting

    -

    Use C++-style casts like static_cast<float>(double_value), or brace initialization for conversion of arithmetic types like @@ -2759,17 +2546,13 @@ initialization for conversion of arithmetic types like cast formats like int y = (int)x or int y = int(x) (but the latter is okay when invoking a constructor of a class type).

    -
    -
    - -
    +

    C++ introduced a different cast system from C that distinguishes the types of cast operations.

    -
    -
    +

    The problem with C casts is the ambiguity of the operation; sometimes you are doing a conversion (e.g., (int)3.5) and sometimes you are doing @@ -2777,13 +2560,11 @@ a cast (e.g., (int)"hello"). Brace initialization and C++ casts can often help avoid this ambiguity. Additionally, C++ casts are more visible when searching for them.

    -
    -
    +

    The C++-style cast syntax is verbose and cumbersome.

    -
    -
    +

    Do not use C-style casts. Instead, use these C++-style casts when explicit type conversion is necessary.

    @@ -2793,7 +2574,7 @@ explicit type conversion is necessary.

    will not compile if conversion can result in information loss. The syntax is also concise. - +
  • Use static_cast as the equivalent of a C-style cast that does value conversion, when you need to @@ -2802,51 +2583,47 @@ explicit type conversion is necessary.

    subclass. In this last case, you must be sure your object is actually an instance of the subclass.
  • - +
  • Use const_cast to remove the const qualifier (see const).
  • -
  • Use reinterpret_cast to do unsafe - conversions of pointer types to and from integer and - other pointer types. Use this only if you know what you - are doing and you understand the aliasing issues. -
  • +
  • Use reinterpret_cast to do unsafe conversions of + pointer types to and from integer and other pointer + types. Use this + only if you know what you are doing and you understand the aliasing + issues. Also, consider the alternative + absl::bit_cast.
  • - +
  • Use absl::bit_cast to interpret the raw bits of a + value using a different type of the same size (a type pun), such as + interpreting the bits of a double as + int64.
  • See the RTTI section for guidance on the use of dynamic_cast.

    -
    - -

    Streams

    -

    Use streams where appropriate, and stick to "simple" usages. Overload << for streaming only for types representing values, and write only the user-visible value, not any implementation details.

    -
    -
    - -
    +

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

    -
    -
    +

    The << and >> stream operators provide an API for formatted I/O that is easily learned, portable, reusable, and extensible. printf, by contrast, doesn't even support -string, to say nothing of user-defined types, +std::string, to say nothing of user-defined types, and is very difficult to use portably. printf also obliges you to choose among the numerous slightly different versions of that function, @@ -2857,9 +2634,8 @@ via std::cin, std::cout, std::cerr, and std::clog. The C APIs do as well, but are hampered by the need to manually buffer the input.

    -
    -
    +

    • Stream formatting can be configured by mutating the state of the stream. Such mutations are persistent, so @@ -2893,9 +2669,8 @@ extremely costly for the compiler. When used pervasively in a large code base, it can consume as much as 20% of the parsing and semantic analysis time.
    -
    -
    +

    Use streams only when they are the best tool for the job. This is typically the case when the I/O is ad-hoc, local, human-readable, and targeted at other developers rather than @@ -2935,30 +2710,22 @@ details in the output of <<; if you need to print object internals for debugging, use named functions instead (a method named DebugString() is the most common convention).

    -
    - -

    Preincrement and Predecrement

    -

    Use prefix form (++i) of the increment and decrement operators with iterators and other template objects.

    -
    -
    - -
    +

    When a variable is incremented (++i or i++) or decremented (--i or i--) and the value of the expression is not used, one must decide whether to preincrement (decrement) or postincrement (decrement).

    -
    -
    +

    When the return value is ignored, the "pre" form (++i) is never less efficient than the "post" form (i++), and is often more @@ -2969,36 +2736,27 @@ iterator or other non-scalar type, copying i could be expensive. Since the two types of increment behave the same when the value is ignored, why not just always pre-increment?

    -
    -
    +

    The tradition developed, in C, of using post-increment when the expression value is not used, especially in for loops. Some find post-increment easier to read, since the "subject" (i) precedes the "verb" (++), just like in English.

    -
    -
    +

    For simple scalar (non-object) values there is no reason to prefer one form and we allow either. For iterators and other template types, use pre-increment.

    -
    - -

    Use of const

    -
    -

    Use const whenever it makes sense. With C++11, +

    In APIs, use const whenever it makes sense. With C++11, constexpr is a better choice for some uses of const.

    -
    -
    - -
    +

    Declared variables and parameters can be preceded by the keyword const to indicate the variables are not changed (e.g., const int foo). Class @@ -3006,9 +2764,8 @@ functions can have the const qualifier to indicate the function does not change the state of the class member variables (e.g., class Foo { int Bar(char c) const; };).

    -
    -
    +

    Easier for people to understand how variables are being used. Allows the compiler to do better type checking, and, conceivably, generate better code. Helps people @@ -3017,23 +2774,24 @@ know the functions they call are limited in how they can modify your variables. Helps people know what functions are safe to use without locks in multi-threaded programs.

    -
    -
    +

    const is viral: if you pass a const variable to a function, that function must have const in its prototype (or the variable will need a const_cast). This can be a particular problem when calling library functions.

    -
    -
    -

    const variables, data members, methods -and arguments add a level of compile-time type checking; -it is better to detect errors as soon as possible. -Therefore we strongly recommend that you use -const whenever it makes sense to do so:

    +

    +

    We strongly recommend using const +in APIs (i.e. on function parameters, methods, and +non-local variables) wherever it is meaningful and accurate. This +provides consistent, mostly compiler-verified documentation +of what objects an operation can mutate. Having +a consistent and reliable way to distinguish reads from writes +is critical to writing thread-safe code, and is useful in +many other contexts as well. In particular:

    • If a function guarantees that it will not modify an argument @@ -3041,25 +2799,28 @@ Therefore we strongly recommend that you use should be a reference-to-const (const T&) or pointer-to-const (const T*), respectively.
    • -
    • Declare methods to be const whenever - possible. Accessors should almost always be - const. Other methods should be const if - they do not modify any data members, do not call any - non-const methods, and do not return a - non-const pointer or - non-const reference to a data member.
    • +
    • For a function parameter passed by value, const has + no effect on the caller, thus is not recommended in function + declarations. See -
    • Consider making data members const - whenever they do not need to be modified after - construction.
    • + + TotW #109. + + +
    • Declare methods to be const unless they + alter the logical state of the object (or enable the user to modify + that state, e.g. by returning a non-const reference, but that's + rare), or they can't safely be invoked concurrently.
    -

    The mutable keyword is allowed but is -unsafe when used with threads, so thread safety should be -carefully considered first.

    -
    +

    Using const on local variables is neither encouraged +nor discouraged.

    + +

    All of a class's const operations should be safe +to invoke concurrently with each other. If that's not feasible, the class must +be clearly documented as "thread-unsafe".

    + -

    Where to put the const

    Some people favor the form int const *foo @@ -3079,45 +2840,35 @@ putting the "adjective" (const) before the

    That said, while we encourage putting const first, we do not require it. But be consistent with the code around you!

    -
    - -

    Use of constexpr

    -

    In C++11, use constexpr to define true constants or to ensure constant initialization.

    -
    -
    - -
    +

    Some variables can be declared constexpr to indicate the variables are true constants, i.e. fixed at compilation/link time. Some functions and constructors can be declared constexpr which enables them to be used in defining a constexpr variable.

    -
    -
    +

    Use of constexpr enables definition of constants with floating-point expressions rather than just literals; definition of constants of user-defined types; and definition of constants with function calls.

    -
    -
    +

    Prematurely marking something as constexpr may cause migration problems if later on it has to be downgraded. Current restrictions on what is allowed in constexpr functions and constructors may invite obscure workarounds in these definitions.

    -
    -
    +

    constexpr definitions enable a more robust specification of the constant parts of an interface. Use constexpr to specify true @@ -3125,17 +2876,13 @@ constants and the functions that support their definitions. Avoid complexifying function definitions to enable their use with constexpr. Do not use constexpr to force inlining.

    -
    - -

    Integer Types

    -

    Of the built-in C++ integer types, the only one used is int. If a program needs a variable of a -different size, use +different size, use a precise-width integer type from <stdint.h>, such as int16_t. If your variable represents a @@ -3146,31 +2893,25 @@ Keep in mind that even if your value won't ever be too large for an int, it may be used in intermediate calculations which may require a larger type. When in doubt, choose a larger type.

    -
    -
    - -
    +

    C++ does not specify the sizes of integer types like int. Typically people assume that short is 16 bits, int is 32 bits, long is 32 bits and long long is 64 bits.

    -
    -
    +

    Uniformity of declaration.

    -
    -
    +

    The sizes of integral types in C++ can vary based on compiler and architecture.

    -
    -
    +

    -<stdint.h> defines types +<cstdint> defines types like int16_t, uint32_t, int64_t, etc. You should always use those in preference to short, unsigned @@ -3198,11 +2939,13 @@ or

    You should not use the unsigned integer types such as + uint32_t, unless there is a valid reason such as representing a bit pattern rather than a number, or you need defined overflow modulo 2^N. In particular, do not use unsigned types to say a number -will never be negative. Instead, use +will never be negative. Instead, use + assertions for this.

    @@ -3215,9 +2958,6 @@ rather than a smaller type.

    Use care when converting integer types. Integer conversions and promotions can cause undefined behavior, leading to security bugs and other problems.

    -
    - -

    On Unsigned Integers

    @@ -3238,18 +2978,11 @@ to use iterators and containers rather than pointers and sizes, try not to mix signedness, and try to avoid unsigned types (except for representing bitfields or modular arithmetic). Do not use an unsigned type merely to assert that a variable is non-negative.

    -
    - -

    64-bit Portability

    -

    Code should be 64-bit and 32-bit friendly. Bear in mind problems of printing, comparisons, and structure alignment.

    -
    - -
    • @@ -3260,20 +2993,24 @@ problems of printing, comparisons, and structure alignment.

      for your particular case, try to avoid or even upgrade APIs that rely on the printf family. Instead use a library supporting typesafe numeric formatting, such as - + + StrCat + or - + + Substitute + for fast simple conversions, - - or std::ostream.

      + + or std::ostream.

      Unfortunately, the PRI macros are the only portable way to specify a conversion for the standard bitwidth typedefs (e.g. int64_t, uint64_t, int32_t, uint32_t, etc). - + Where possible, avoid passing arguments of types specified by bitwidth typedefs to printf-based APIs. Note that it is acceptable to use typedefs for which printf has dedicated length modifiers, such as @@ -3288,13 +3025,13 @@ problems of printing, comparisons, and structure alignment.

    • You may need to be careful with structure alignments, particularly for structures being stored on - disk. Any class/structure with a + disk. Any class/structure with a int64_t/uint64_t member will by default end up being 8-byte aligned on a 64-bit system. If you have such structures being shared on disk between 32-bit and 64-bit code, you will need to ensure that they are packed the same on both - architectures. + architectures. Most compilers offer a way to alter structure alignment. For gcc, you can use __attribute__((packed)). MSVC offers @@ -3306,24 +3043,20 @@ problems of printing, comparisons, and structure alignment.

      64-bit constants. For example:

      +
      int64_t my_value{0x123456789};
       uint64_t my_mask{3ULL << 48};
       
      +
    -
    -

    Preprocessor Macros

    -

    Avoid defining macros, especially in headers; prefer inline functions, enums, and const variables. Name macros with a project-specific prefix. Do not use macros to define pieces of a C++ API.

    -
    - -

    Macros mean that the code you see is not the same as the code the compiler sees. This can introduce unexpected @@ -3368,7 +3101,7 @@ lower-level libraries. And some of their special features available through the language proper. But before using a macro, consider carefully whether there's a non-macro way to achieve the same result. If you need to use a macro to -define an interface, contact +define an interface, contact your project leads to request a waiver of this rule.

    @@ -3401,18 +3134,10 @@ header, it must have a globally unique name. To achieve this, it must be named with a prefix consisting of your project's namespace name (but upper case).

    -
    -

    0 and nullptr/NULL

    -
    -

    Use 0 for integers, 0.0 for reals, -nullptr for pointers, and '\0' for chars.

    -
    - -
    - -

    Use 0 for integers and 0.0 for reals.

    +

    Use nullptr for pointers, and '\0' for chars (and +not the 0 literal).

    For pointers (address values), use nullptr, as this provides type-safety.

    @@ -3420,21 +3145,16 @@ provides type-safety.

    For C++03 projects, prefer NULL to 0. While the values are equivalent, NULL looks more like a pointer to the reader, and some C++ compilers provide special definitions of NULL -which enable them to give useful warnings.

    +which enable them to give useful warnings. Never use NULL for +numeric (integer or floating-point) values.

    Use '\0' for the null character. Using the correct type makes the code more readable.

    -
    -

    sizeof

    -

    Prefer sizeof(varname) to sizeof(type).

    -
    - -

    Use sizeof(varname) when you take the size of a particular variable. @@ -3459,20 +3179,14 @@ memset(&data, 0, sizeof(data)); } -

    -

    auto

    -

    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.

    -
    -
    - -
    +

    • C++ type names can be long and cumbersome, especially when they @@ -3483,9 +3197,8 @@ small code region, the repetition may not be aiding readability.
    • the initialization expression, since that avoids the possibility of unintended copies or type conversions.
    -
    -
    +

    Sometimes code is clearer when types are manifest, especially when a variable's initialization depends on things that were declared far away. In expressions @@ -3508,10 +3221,8 @@ interface, e.g. as a constant in a header, then a programmer might change its type while only intending to change its value, leading to a more radical API change than intended.

    -
    - -
    +

    auto is permitted when it increases readability, particularly as described below. Never initialize an auto-typed variable with a braced initializer list.

    @@ -3525,7 +3236,7 @@ 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 and +to new and std::make_unique commonly falls into this category, as does use of auto in a range-based loop over a container whose type is spelled out @@ -3539,7 +3250,7 @@ is std::pair<KeyType, ValueType> whereas it is actually particularly well paired with local key and value aliases for .first and .second (often const-ref). -
    for (const auto& item : some_map) {
    +
    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,
    @@ -3550,115 +3261,14 @@ and .second (often const-ref).
     
  • -
    -
    - -

    Braced Initializer List

    - -
    -

    You may use braced initializer lists.

    -
    - -
    - -

    In C++03, aggregate types (arrays and structs with no -constructor) could be initialized with braced initializer lists.

    - -
    struct Point { int x; int y; };
    -Point p = {1, 2};
    -
    - -

    In C++11, this syntax was generalized, and any object type can now -be created with a braced initializer list, known as a -braced-init-list in the C++ grammar. Here are a few examples -of its use.

    - -
    // Vector takes a braced-init-list of elements.
    -std::vector<string> v{"foo", "bar"};
    -
    -// Basically the same, ignoring some small technicalities.
    -// You may choose to use either form.
    -std::vector<string> v = {"foo", "bar"};
    -
    -// Usable with 'new' expressions.
    -auto p = new std::vector<string>{"foo", "bar"};
    -
    -// A map can take a list of pairs. Nested braced-init-lists work.
    -std::map<int, string> m = {{1, "one"}, {2, "2"}};
    -
    -// A braced-init-list can be implicitly converted to a return type.
    -std::vector<int> test_function() { return {1, 2, 3}; }
    -
    -// Iterate over a braced-init-list.
    -for (int i : {-1, -2, -3}) {}
    -
    -// Call a function using a braced-init-list.
    -void TestFunction2(std::vector<int> v) {}
    -TestFunction2({1, 2, 3});
    -
    - -

    A user-defined type can also define a constructor and/or assignment operator -that take std::initializer_list<T>, which is automatically -created from braced-init-list:

    - -
    class MyType {
    - public:
    -  // std::initializer_list references the underlying init list.
    -  // It should be passed by value.
    -  MyType(std::initializer_list<int> init_list) {
    -    for (int i : init_list) append(i);
    -  }
    -  MyType& operator=(std::initializer_list<int> init_list) {
    -    clear();
    -    for (int i : init_list) append(i);
    -  }
    -};
    -MyType m{2, 3, 5, 7};
    -
    - -

    Finally, brace initialization can also call ordinary -constructors of data types, even if they do not have -std::initializer_list<T> constructors.

    - -
    double d{1.23};
    -// Calls ordinary constructor as long as MyOtherType has no
    -// std::initializer_list constructor.
    -class MyOtherType {
    - public:
    -  explicit MyOtherType(string);
    -  MyOtherType(int, string);
    -};
    -MyOtherType m = {1, "b"};
    -// If the constructor is explicit, you can't use the "= {}" form.
    -MyOtherType m{"b"};
    -
    - -

    Never assign a braced-init-list to an auto -local variable. In the single element case, what this -means can be confusing.

    - -
    auto d = {1.23};        // d is a std::initializer_list<double>
    -
    - -
    auto d = double{1.23};  // Good -- d is a double, not a std::initializer_list.
    -
    - -

    See Braced_Initializer_List_Format for formatting.

    - -

    Lambda expressions

    -

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

    -
    - -
    - -
    +

    Lambda expressions are a concise way of creating anonymous function objects. They're often useful when passing functions as arguments. For example:

    @@ -3698,9 +3308,8 @@ std::sort(indices.begin(), indices.end(), [&](int a, int b) { for working with function objects, such as the polymorphic wrapper std::function.

    -
    -
    +

    • Lambdas are much more concise than other ways of defining function objects to be passed to STL @@ -3717,9 +3326,8 @@ wrapper std::function. to write functions that take bound functions as arguments.
    -
    -
    +

    • Variable capture in lambdas can be a source of dangling-pointer bugs, particularly if a lambda escapes the current scope.
    • @@ -3735,9 +3343,8 @@ wrapper std::function. code harder to understand.
    -
    -
    +

    • Use lambda expressions where appropriate, with formatting as described below.
    • @@ -3781,40 +3388,32 @@ make it more obvious to readers, as with auto.
    -
    - -

    Template metaprogramming

    -
    +

    Avoid complicated template programming.

    -
    -
    - -
    +

    Template metaprogramming refers to a family of techniques that exploit the fact that the C++ template instantiation mechanism is Turing complete and can be used to perform arbitrary compile-time computation in the type domain.

    -
    -
    +

    Template metaprogramming allows extremely flexible interfaces that are type safe and high performance. Facilities like Google Test, std::tuple, std::function, and Boost.Spirit would be impossible without it.

    -
    -
    +

    The techniques used in template metaprogramming are often obscure to anyone but language experts. Code that uses templates in complicated ways is often unreadable, and is hard to debug or maintain.

    -

    Template metaprogramming often leads to extremely poor compiler +

    Template metaprogramming often leads to extremely poor compile time error messages: even if an interface is simple, the complicated implementation details become visible when the user does something wrong.

    @@ -3827,9 +3426,8 @@ tools work with an AST that only represents the structure of the code after template expansion. It can be difficult to automatically work back to the original source construct that needs to be rewritten.

    -
    -
    +

    Template metaprogramming sometimes allows cleaner and easier-to-use interfaces than would be possible without it, but it's also often a temptation to be overly clever. It's best used in a small number of @@ -3860,42 +3458,31 @@ error messages are part of your user interface, and your code should be tweaked as necessary so that the error messages are understandable and actionable from a user point of view.

    -
    -
    - -

    Boost

    -

    Use only approved libraries from the Boost library collection.

    -
    -
    - -
    +

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

    -
    -
    +

    Boost code is generally very high-quality, is widely portable, and fills many important gaps in the C++ standard library, such as type traits and better binders.

    -
    -
    +

    Some Boost libraries encourage coding practices which can hamper readability, such as metaprogramming and other advanced template techniques, and an excessively "functional" style of programming.

    -
    -
    +

    + -

    In order to maintain a high level of readability for @@ -3943,6 +3530,9 @@ Currently, the following libraries are permitted:

  • Special Functions from boost/math/special_functions
  • +
  • + Root Finding Functions from boost/math/tools
  • +
  • Multi-index from boost/multi_index
  • @@ -3967,44 +3557,21 @@ Currently, the following libraries are permitted:

    We are actively considering adding other Boost features to the list, so this list may be expanded in the future.

    -
    +
    -

    The following libraries are permitted, but their use -is discouraged because they've been superseded by -standard libraries in C++11:

    - -
    - -
    - -

    std::hash

    -

    Do not define specializations of std::hash.

    -
    -
    - -
    +

    std::hash<T> is the function object that the C++11 hash containers use to hash keys of type T, unless the user explicitly specifies a different hash function. For -example, std::unordered_map<int, string> is a hash +example, std::unordered_map<int, std::string> is a hash map that uses std::hash<int> to hash its keys, -whereas std::unordered_map<int, string, MyIntHash> +whereas std::unordered_map<int, std::string, MyIntHash> uses MyIntHash.

    std::hash is defined for all integral, floating-point, @@ -4012,17 +3579,15 @@ pointer, and enum types, as well as some standard library types such as string and unique_ptr. Users can enable it to work for their own types by defining specializations of it for those types.

    -
    -
    +

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

    -
    -
    +

    std::hash is hard to specialize. It requires a lot of boilerplate code, and more importantly, it combines responsibility for identifying the hash inputs with responsibility for executing the @@ -4046,9 +3611,8 @@ should not be done more than once.

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

    -
    -
    +

    You can use std::hash with the types that it supports "out of the box", but do not specialize it to support additional types. If you need a hash table with a key type that std::hash @@ -4067,37 +3631,27 @@ that you can use; otherwise work with them to provide one,

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

    -
    - -

    C++11

    -

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

    -
    - -
    - -
    +

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

    -
    -
    +

    C++11 was the official standard until 2014, and is supported by most C++ compilers. It standardizes some common C++ extensions that we use already, allows shorthands for some operations, and has some performance and safety improvements.

    -
    -
    +

    The C++11 standard is substantially more complex than its predecessor (1,300 pages versus 800 pages), and is unfamiliar to many developers. The long-term effects of @@ -4117,22 +3671,14 @@ available through existing mechanisms, which may lead to confusion and conversion costs.

    -
    - -
    +

    C++11 features may be used unless specified otherwise. In addition to what's described in the rest of the style guide, the following C++11 features may not be used:

      - - - - - -
    • Compile-time rational numbers (<ratio>), because of concerns that @@ -4143,21 +3689,14 @@ guide, the following C++11 features may not be used:

      <fenv.h> headers, because many compilers do not support those features reliably.
    • - -
    -
    - -

    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. @@ -4166,9 +3705,8 @@ guide, the following C++11 features may not be used:

    foo = ({ int x; Bar(&x); x }), variable-length arrays and alloca(), and the "Elvis Operator" a?:b.

    -
    -
    +

    • Nonstandard extensions may provide useful features that do not exist in standard C++. For example, some people think that designated @@ -4177,9 +3715,8 @@ guide, the following C++11 features may not be used:

    • 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.
    • @@ -4189,24 +3726,19 @@ guide, the following C++11 features may not be used:

    • 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

    -

    Public aliases are for the benefit of an API's user, and should be clearly documented.

    -
    -
    -
    + +

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

    typedef Foo Bar;
     using Bar = Foo;
    @@ -4222,18 +3754,16 @@ using other_namespace::Foo;
       or in an explicitly-marked internal namespace. Aliases in such areas or in .cc files are
       implementation details (because client code can't refer to them), and are not restricted by this
       rule.

    -
    -
    +

    • Aliases can improve readability by simplifying a long or complicated name.
    • Aliases can reduce duplication by naming in one place a type used repeatedly in an API, which might make it easier to change the type later.
    -
    -
    +

    • When placed in a header where client code can refer to them, aliases increase the number of entities in that header's API, increasing its complexity.
    • @@ -4247,9 +3777,8 @@ using other_namespace::Foo; 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
    -
    -
    +

    Don't put an alias in your public API just to save typing in the implementation; do so only if you intend it to be used by your clients.

    When defining a public alias, document the intent of @@ -4290,9 +3819,6 @@ typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator&g using foo::Bar; -

    -
    -

    Naming

    The most important consistency rules are those that govern @@ -4311,49 +3837,68 @@ the rules are the rules.

    General Naming Rules

    -
    -

    Names should be descriptive; avoid abbreviation.

    -
    +

    Optimize for readability using names that would be clear +even to people on a different team.

    -
    -

    Give as descriptive a name as possible, within reason. +

    Use names that describe the purpose or intent of the object. Do not worry about saving horizontal space as it is far more important to make your code immediately -understandable by a new reader. Do not use abbreviations -that are ambiguous or unfamiliar to readers outside your -project, and do not abbreviate by deleting letters within -a word. Abbreviations that would be familiar to someone -outside your project with relevant domain knowledge are OK. -As a rule of thumb, an abbreviation is probably OK if it's listed -in +understandable by a new reader. Minimize the use of +abbreviations that would likely be unknown to someone outside +your project (especially acronyms and initialisms). Do not +abbreviate by deleting letters within a word. As a rule of thumb, +an abbreviation is probably OK if it's listed in + Wikipedia. Generally speaking, descriptiveness should be +proportional to the name's scope of visibility. For example, +n may be a fine name within a 5-line function, +but within the scope of a class, it's likely too vague.

    -Wikipedia.

    - -
    int price_count_reader;    // No abbreviation.
    -int num_errors;            // "num" is a widespread convention.
    -int num_dns_connections;   // Most people know what "DNS" stands for.
    -int lstm_size;             // "LSTM" is a common machine learning abbreviation.
    +
    class MyClass {
    + public:
    +  int CountFooErrors(const std::vector<Foo>& foos) {
    +    int n = 0;  // Clear meaning given limited scope and context
    +    for (const auto& foo : foos) {
    +      ...
    +      ++n;
    +    }
    +    return n;
    +  }
    +  void DoSomethingImportant() {
    +    std::string fqdn = ...;  // Well-known abbreviation for Fully Qualified Domain Name
    +  }
    + private:
    +  const int kMaxAllowedConnections = ...;  // Clear meaning within context
    +};
     
    -
    int n;                     // Meaningless.
    -int nerr;                  // Ambiguous abbreviation.
    -int n_comp_conns;          // Ambiguous abbreviation.
    -int wgc_connections;       // Only your group knows what this stands for.
    -int pc_reader;             // Lots of things can be abbreviated "pc".
    -int cstmr_id;              // Deletes internal letters.
    -FooBarRequestInfo fbri;    // Not even a word.
    +
    class MyClass {
    + public:
    +  int CountFooErrors(const std::vector<Foo>& foos) {
    +    int total_number_of_foo_errors = 0;  // Overly verbose given limited scope and context
    +    for (int foo_index = 0; foo_index < foos.size(); ++foo_index) {  // Use idiomatic `i`
    +      ...
    +      ++total_number_of_foo_errors;
    +    }
    +    return total_number_of_foo_errors;
    +  }
    +  void DoSomethingImportant() {
    +    int cstmr_id = ...;  // Deletes internal letters
    +  }
    + private:
    +  const int kNum = ...;  // Unclear meaning within broad scope
    +};
     

    Note that certain universally-known abbreviations are OK, such as i for an iteration variable and T for a template parameter.

    -

    For some symbols, this style guide recommends names to start with a capital -letter and to have a capital letter for each new word (a.k.a. -"Camel Case" -or "Pascal case"). When abbreviations or acronyms appear in such -names, prefer to capitalize the abbreviations or acronyms as single words (i.e -StartRpc(), not StartRPC()).

    +

    For the purposes of the naming rules below, a "word" is anything that you +would write in English without internal spaces. This includes abbreviations and +acronyms; e.g., for "camel +case" or "Pascal case," in which the first letter of each word is +capitalized, use a name like StartRpc(), not +StartRPC().

    Template parameters should follow the naming style for their category: type template parameters should follow the rules for @@ -4361,20 +3906,14 @@ category: type template parameters should follow the rules for parameters should follow the rules for variable names. -

    +

    File Names

    -

    File Names

    - -

    Filenames should be all lowercase and can include underscores (_) or dashes (-). Follow the convention that your - + project uses. If there is no consistent local pattern to follow, prefer "_".

    -
    - -

    Examples of acceptable file names:

    @@ -4400,17 +3939,11 @@ of files called, e.g., foo_bar.h and foo_bar.cc, defining a class called FooBar.

    -
    -

    Type Names

    -

    Type names start with a capital letter and have a capital letter for each new word, with no underscores: MyExcitingClass, MyExcitingEnum.

    -
    - -

    The names of all types — classes, structs, type aliases, enums, and type template parameters — have the same naming convention. @@ -4423,41 +3956,34 @@ class UrlTableTester { ... struct UrlTableProperties { ... // typedefs -typedef hash_map<UrlTableProperties *, string> PropertiesMap; +typedef hash_map<UrlTableProperties *, std::string> PropertiesMap; // using aliases -using PropertiesMap = hash_map<UrlTableProperties *, string>; +using PropertiesMap = hash_map<UrlTableProperties *, std::string>; // enums enum UrlTableErrors { ... -

    -

    Variable Names

    -

    The names of variables (including function parameters) and data members are all lowercase, with underscores between words. Data members of classes (but not structs) additionally have trailing underscores. For instance: a_local_variable, a_struct_data_member, a_class_data_member_.

    -
    -
    - -

    Common Variable names

    +

    Common Variable names

    For example:

    -
    string table_name;  // OK - uses underscore.
    -string tablename;   // OK - all lowercase.
    +
    std::string table_name;  // OK - lowercase with underscore.
     
    -
    string tableName;   // Bad - mixed case.
    +
    std::string tableName;   // Bad - mixed case.
     
    -

    Class Data Members

    +

    Class Data Members

    Data members of classes, both static and non-static, are named like ordinary nonmember variables, but with a @@ -4466,20 +3992,19 @@ trailing underscore.

    class TableInfo {
       ...
      private:
    -  string table_name_;  // OK - underscore at end.
    -  string tablename_;   // OK.
    +  std::string table_name_;  // OK - underscore at end.
       static Pool<TableInfo>* pool_;  // OK.
     };
     
    -

    Struct Data Members

    +

    Struct Data Members

    Data members of structs, both static and non-static, are named like ordinary nonmember variables. They do not have the trailing underscores that data members in classes have.

    struct UrlTableProperties {
    -  string name;
    +  std::string name;
       int num_entries;
       static Pool<UrlTableProperties>* pool;
     };
    @@ -4490,39 +4015,27 @@ the trailing underscores that data members in classes have.

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

    -
    -

    Constant Names

    -
    -

    Variables declared constexpr or const, and whose value is fixed for - the duration of the program, are named with a leading "k" followed - by mixed case. Underscores can be used as separators in the rare cases - where capitalization cannot be used for separation. For example:

    -
    +

    Variables declared constexpr or const, and whose value is fixed for +the duration of the program, are named with a leading "k" followed +by mixed case. 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 kAndroid8_0_0 = 24;  // Android 8.0.0
     
    -
    - -

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

    - -
    +

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

    Function Names

    -

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

    -
    - -

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

    @@ -4542,18 +4055,13 @@ variables. These often correspond to actual member variables, but this is not required. For example, int count() and void set_count(int count).

    -
    -

    Namespace Names

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

    The name of a top-level namespace should usually be the name of the project or team whose code is contained in that namespace. The code in that namespace should usually be in @@ -4562,8 +4070,6 @@ subdirectories thereof).

    - -

    Keep in mind that the rule against abbreviated names applies to namespaces just as much as variable names. Code inside the namespace seldom needs to @@ -4586,18 +4092,12 @@ internal name is helpful (websearch::index::frobber_internal for use in frobber.h)

    -
    -

    Enumerator Names

    -

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

    -
    - -

    Preferably, the individual enumerators should be named like constants. However, it @@ -4608,7 +4108,7 @@ is also acceptable to name them like therefore mixed case.

    enum UrlTableErrors {
    -  kOK = 0,
    +  kOk = 0,
       kErrorOutOfMemory,
       kErrorMalformedInput,
     };
    @@ -4630,18 +4130,12 @@ names are actually causing a compile-time problem.

    -
    -

    Macro Names

    -

    You're not really going to define a macro, are you? If you do, they're like this: MY_MACRO_THAT_SCARES_SMALL_CHILDREN_AND_ADULTS_ALIKE.

    -
    - -

    Please see the description of macros; in general macros should not be used. @@ -4652,17 +4146,11 @@ named with all capitals and underscores.

    #define PI_ROUNDED 3.0 -
    -

    Exceptions to Naming Rules

    -

    If you are naming something that is analogous to an existing C or C++ entity then you can follow the existing naming convention scheme.

    -
    - -
    bigopen()
    @@ -4682,69 +4170,58 @@ naming convention scheme.

    a constant, as in INT_MAX
    -
    -

    Comments

    -

    Though a pain to write, comments are absolutely vital to -keeping our code readable. The following rules describe what -you should comment and where. But remember: while comments are -very important, the best code is self-documenting. Giving -sensible names to types and variables is much better than using -obscure names that you must then explain through comments.

    +

    Comments are absolutely vital to keeping our code readable. The following rules describe what you +should comment and where. But remember: while comments are very important, the best code is +self-documenting. Giving sensible names to types and variables is much better than using obscure +names that you must then explain through comments.

    When writing your comments, write for your audience: the -next +next contributor who will need to understand your code. Be generous — the next one may be you!

    Comment Style

    -

    Use either the // or /* */ syntax, as long as you are consistent.

    -
    - -

    You can use either the // or the /* */ syntax; however, // is much more common. Be consistent with how you comment and what style you use where.

    -
    -

    File Comments

    -
    +

    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.

    -
    - -
    - -

    Legal Notice and Author +

    Legal Notice and Author Line

    +

    Every file should contain license boilerplate. Choose the appropriate boilerplate for the license used by the project (for example, Apache 2.0, BSD, LGPL, GPL).

    +

    If you make significant changes to a file with an author line, consider deleting the author line. New files should usually not contain copyright notice or author line.

    -

    File Contents

    +

    File Contents

    If a .h declares multiple abstractions, the file-level comment should broadly describe the contents of the file, and how the abstractions are @@ -4755,16 +4232,10 @@ not at the file level.

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

    -
    -

    Class Comments

    -

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

    -
    - -
    // Iterates over the contents of a GargantuanTable.
     // Example:
    @@ -4793,29 +4264,24 @@ 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 (when it is non-obvious); comments at the definition of a function describe operation.

    -
    -
    - -

    Function Declarations

    +

    Function Declarations

    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.

    +class). These comments should open with descriptive verbs in the +indicative mood ("Opens the file") rather than verbs in the 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:

    @@ -4879,7 +4345,7 @@ cleanup the destructor does. If this is trivial, just skip the comment. It is quite common for destructors not to have a header comment.

    -

    Function Definitions

    +

    Function Definitions

    If there is anything tricky about how a function does its job, the function definition should have an @@ -4898,19 +4364,13 @@ given with the function declaration, in the recapitulate briefly what the function does, but the focus of the comments should be on how it does it.

    -
    -

    Variable Comments

    -

    In general the actual name of the variable should be descriptive enough to give a good idea of what the variable is used for. In certain cases, more comments are required.

    -
    -
    - -

    Class Data Members

    +

    Class Data Members

    The purpose of each class data member (also called an instance variable or member variable) must be clear. If there are any @@ -4929,7 +4389,7 @@ obvious. For example:

    int num_total_entries_; -

    Global Variables

    +

    Global Variables

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

    const int kNumTestCases = 6; -
    -

    Implementation Comments

    -

    In your implementation you should have comments in tricky, non-obvious, interesting, or important parts of your code.

    -
    -
    - -

    Explanatory Comments

    +

    Explanatory Comments

    Tricky or complicated code blocks should have comments before them. Example:

    -
    // Divides result by two, taking into account that x
    +
    // Divide result by two, taking into account that x
     // contains the carry from the add.
    -for (int i = 0; i < result->size(); i++) {
    +for (int i = 0; i < result->size(); ++i) {
       x = (x << 8) + (*result)[i];
       (*result)[i] = x >> 1;
       x &= 1;
     }
     
    -

    Line Comments

    +

    Line-end Comments

    Also, lines that are non-obvious should get a comment at the end of the line. These end-of-line comments should @@ -4981,24 +4435,7 @@ the code is doing, and comments that mention that an error has already been logged when the function returns.

    -

    If you have several comments on subsequent lines, it -can often be more readable to line them up:

    - -
    DoSomething();                  // Comment here so the comments line up.
    -DoSomethingElseThatIsLonger();  // Two spaces between the code and the comment.
    -{ // One space before comment when opening a new scope is allowed,
    -  // thus the comment lines up with the following comments and code.
    -  DoSomethingElse();  // Two spaces before line comments normally.
    -}
    -std::vector<string> list{
    -                    // Comments in braced lists describe the next element...
    -                    "First item",
    -                    // .. and should be aligned appropriately.
    -                    "Second item"};
    -DoSomething(); /* For trailing block comments, one space is fine. */
    -
    - -

    Function Argument Comments

    +

    Function Argument Comments

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

    @@ -5045,7 +4482,7 @@ const DecimalNumber product = CalculateProduct(values, options, /*completion_callback=*/nullptr);
    -

    Don'ts

    +

    Don'ts

    Do not state the obvious. In particular, don't literally describe what code does, unless the behavior is nonobvious to a reader who understands @@ -5078,17 +4515,11 @@ the example above would be obvious: } -

    +

    Punctuation, Spelling, and Grammar

    -

    Punctuation, Spelling and Grammar

    - -

    Pay attention to punctuation, spelling, and grammar; it is easier to read well-written comments than badly written ones.

    -
    - -

    Comments should be as readable as narrative text, with proper capitalization and punctuation. In many cases, @@ -5104,16 +4535,10 @@ maintain a high level of clarity and readability. Proper punctuation, spelling, and grammar help with that goal.

    -
    -

    TODO Comments

    -

    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 @@ -5144,50 +4569,6 @@ very specific date ("Fix by November 2005") or a very specific event ("Remove this code when all clients can handle XML responses.").

    -
    - -

    Deprecation Comments

    - -
    -

    Mark deprecated interface points with DEPRECATED -comments.

    -
    - -
    - -

    You can mark an interface as deprecated by writing a -comment containing the word DEPRECATED in -all caps. The comment goes either before the declaration -of the interface or on the same line as the -declaration.

    - - - -

    After the word -DEPRECATED, write your name, e-mail address, -or other identifier in parentheses.

    - -

    A deprecation comment must include simple, clear -directions for people to fix their callsites. In C++, you -can implement a deprecated function as an inline function -that calls the new interface point.

    - -

    Marking an interface point DEPRECATED -will not magically cause any callsites to change. If you -want people to actually stop using the deprecated -facility, you will have to fix the callsites yourself or -recruit a crew to help you.

    - -

    New code should not contain calls to deprecated -interface points. Use the new interface point instead. If -you cannot understand the directions, find the person who -created the deprecation and ask them for help using the -new interface point.

    - - - -
    -

    Formatting

    Coding style and formatting are pretty arbitrary, but a @@ -5198,33 +4579,32 @@ aspect of the formatting rules, and some of the rules may take some getting used to, but it is important that all project contributors follow the -style rules so that +style rules so that they can all read and understand everyone's code easily.

    -

    To help you format code correctly, we've -created a +

    +

    To help you format code correctly, we've created a settings file for emacs.

    +

    Line Length

    -

    Each line of text in your code should be at most 80 characters long.

    -
    - -
    -

    We recognize that this rule is +

    +

    We recognize that this rule is controversial, but so much existing code already adheres to it, and we feel that consistency is important.

    +
    -
    +

    Those who favor this rule argue that it is rude to force them to resize their windows and there is no need for anything longer. @@ -5234,16 +4614,14 @@ windows in any case. People set up their work environment assuming a particular maximum window width, and 80 columns has been the traditional standard. Why change it?

    -
    -
    +

    Proponents of change argue that a wider line can make code more readable. The 80-column limit is an hidebound throwback to 1960s mainframes; modern equipment has wide screens that can easily show longer lines.

    -
    -
    +

    80 characters is the maximum.

    A line may exceed 80 characters if it is

    @@ -5263,18 +4641,10 @@ can easily show longer lines.

  • a using-declaration
  • -
    - -
    -

    Non-ASCII Characters

    -

    Non-ASCII characters should be rare, and must use UTF-8 formatting.

    -
    - -

    You shouldn't hard-code user-facing text in source, even English, so use of non-ASCII characters should be @@ -5311,32 +4681,20 @@ use wchar_t (unless you're writing code that interacts with the Windows API, which uses wchar_t extensively).

    -
    -

    Spaces vs. Tabs

    -

    Use only spaces, and indent 2 spaces at a time.

    -
    - -

    We use spaces for indentation. Do not use tabs in your code. You should set your editor to emit spaces when you hit the tab key.

    -
    -

    Function Declarations and Definitions

    -

    Return type on the same line as function name, parameters on the same line if they fit. Wrap parameter lists which do not fit on a single line as you would wrap arguments in a function call.

    -
    - -

    Functions look like this:

    @@ -5410,10 +4768,8 @@ not fit on a single line as you would wrap arguments in a
    class Foo {
      public:
    -  Foo(Foo&&);
    -  Foo(const Foo&);
    -  Foo& operator=(Foo&&);
    -  Foo& operator=(const Foo&);
    +  Foo(const Foo&) = delete;
    +  Foo& operator=(const Foo&) = delete;
     };
     
    @@ -5441,19 +4797,14 @@ 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();
    +
    ABSL_MUST_USE_RESULT bool IsOk();
     
    -
    -

    Lambda Expressions

    -

    Format parameters and bodies as for any other function, and capture 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;
    @@ -5468,20 +4819,38 @@ digits.erase(std::remove_if(digits.begin(), digits.end(), [&blacklist](int i
                  digits.end());
     
    -
    +

    Floating-point Literals

    + +

    Floating-point literals should always have a radix point, with digits on both +sides, even if they use exponential notation. Readability is improved if all +floating-point literals take this familiar form, as this helps ensure that they +are not mistaken for integer literals, and that the +E/e of the exponential notation is not mistaken for a +hexadecimal digit. It is fine to initialize a floating-point variable with an +integer literal (assuming the variable type can exactly represent that integer), +but note that a number in exponential notation is never an integer literal. +

    + +
    float f = 1.f;
    +long double ld = -.5L;
    +double d = 1248e6;
    +
    + +
    float f = 1.0f;
    +float f2 = 1;   // Also OK
    +long double ld = -0.5L;
    +double d = 1248.0e6;
    +
    +

    Function Calls

    -

    Either write the call all on a single line, wrap the arguments at the parenthesis, or start the arguments on a new line indented by four spaces and continue at that 4 space indent. In the absence of other considerations, use the 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);
    @@ -5546,16 +4915,10 @@ my_widget.Transform(x1, x2, x3,
                         z1, z2, z3);
     
    -
    -

    Braced Initializer List Format

    -

    Format a braced initializer list exactly like you would format a function call in its place.

    -
    - -

    If the braced list follows a name (e.g. a type or variable name), format as if the {} were the @@ -5589,16 +4952,10 @@ MyType m = { // Here, you could also break before {. interiorwrappinglist2}}; -

    -

    Conditionals

    -

    Prefer no spaces inside parentheses. The if and else keywords belong on separate lines.

    -
    - -

    There are two acceptable formats for a basic conditional statement. One includes spaces between the @@ -5664,7 +5021,7 @@ else DoThat(); single-line statements, but they are allowed if you like them; conditional or loop statements with complex conditions or statements may be more readable with curly -braces. Some +braces. Some projects require that an if must always have an accompanying brace.

    @@ -5704,18 +5061,12 @@ if (condition) { } -
    -

    Loops and Switch Statements

    -

    Switch statements may use braces for blocks. Annotate non-trivial fall-through between cases. Braces are optional for single-statement loops. Empty loop bodies should use either empty braces or continue.

    -
    - -

    case blocks in switch statements can have curly braces or not, depending on @@ -5728,7 +5079,7 @@ statements should always have a default case warn you if any values are not handled). If the default case should never execute, treat this as an error. For example: -

    +

    switch (var) {
    @@ -5745,7 +5096,7 @@ case should never execute, treat this as an error. For example:
       }
     }
     
    -
    +

    Fall-through from one case label to another must be annotated using the @@ -5758,7 +5109,6 @@ label occurs. A common exception is consecutive case labels without intervening code, in which case no annotation is needed.

    -
    switch (x) {
       case 41:  // No annotation needed here.
       case 43:
    @@ -5777,7 +5127,6 @@ annotation is needed.

    break; }
    -

    Braces are optional for single-statement loops.

    @@ -5803,16 +5152,10 @@ while (condition) continue; // Good - continue indicates no logic.
    while (condition);  // Bad - looks like part of do/while loop.
     
    - -

    Pointer and Reference Expressions

    -

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

    -
    - -

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

    @@ -5839,11 +5182,11 @@ variable name:

    // These are fine, space preceding.
     char *c;
    -const string &str;
    +const std::string &str;
     
     // These are fine, space following.
     char* c;
    -const string& str;
    +const std::string& str;
     

    You should do this consistently within a single @@ -5859,20 +5202,14 @@ int x, y;

    int x, *y;  // Disallowed - no & or * in multiple declaration
     char * c;  // Bad - spaces on both sides of *
    -const string & str;  // Bad - spaces on both sides of &
    +const std::string & str;  // Bad - spaces on both sides of &
     
    -
    -

    Boolean Expressions

    -

    When you have a boolean expression that is longer than the standard line length, be consistent in how you break up the lines.

    -
    - -

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

    @@ -5897,16 +5234,10 @@ the punctuation operators, such as the word operators, such as and and compl.

    -
    -

    Return Values

    -

    Do not needlessly surround the return expression with parentheses.

    -
    - -

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

    @@ -5921,18 +5252,12 @@ return (some_long_condition && return(result); // return is not a function! -
    -

    Variable and Array Initialization

    -

    Your choice of =, (), or {}.

    -
    - -

    You may choose between =, (), and {}; the following are @@ -5941,9 +5266,9 @@ all correct:

    int x = 3;
     int x(3);
     int x{3};
    -string name = "Some Name";
    -string name("Some Name");
    -string name{"Some Name"};
    +std::string name = "Some Name";
    +std::string name("Some Name");
    +std::string name{"Some Name"};
     

    Be careful when using a braced initialization list {...} @@ -5967,16 +5292,10 @@ errors.

    int pi{3.14}; // Compile error: narrowing conversion. -
    -

    Preprocessor Directives

    -

    The hash mark that starts a preprocessor directive should always be at the beginning of the line.

    -
    - -

    Even when preprocessor directives are within the body of indented code, the directives should start at the @@ -6003,16 +5322,10 @@ beginning of the line.

    } -
    -

    Class Format

    -

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

    -
    - -

    The basic format for a class definition (lacking the comments, see Class @@ -6066,16 +5379,10 @@ needed) is:

    each of these sections. -
    -

    Constructor Initializer Lists

    -

    Constructor initializer lists can be all on one line or with subsequent lines indented four spaces.

    -
    - -

    The acceptable formats for initializer lists are:

    @@ -6105,15 +5412,9 @@ MyClass::MyClass(int var) : some_var_(var) {} -
    -

    Namespace Formatting

    -

    The contents of namespaces are not indented.

    -
    - -

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

    @@ -6146,18 +5447,12 @@ on its own line.

    namespace bar { -
    -

    Horizontal Whitespace

    -

    Use of horizontal whitespace depends on location. Never put trailing whitespace at the end of a line.

    -
    -
    - -

    General

    +

    General

    void f(bool b) {  // Open braces should always have a space before them.
       ...
    @@ -6182,11 +5477,11 @@ 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 
    +clean-up
     operation (preferably when no-one
     else is working on the file).

    -

    Loops and Conditionals

    +

    Loops and Conditionals

    if (b) {          // Space after the keyword in conditions and loops.
     } else {          // Spaces around else.
    @@ -6214,7 +5509,7 @@ switch (i) {
       case 2: break;  // Use a space after a colon if there's code after it.
     
    -

    Operators

    +

    Operators

    // Assignment operators always have spaces around them.
     x = 0;
    @@ -6233,26 +5528,20 @@ if (x && !y)
       ...
     
    -

    Templates and Casts

    +

    Templates and Casts

    // No spaces inside the angle brackets (< and >), before
     // <, or between >( in a cast
    -std::vector<string> x;
    +std::vector<std::string> x;
     y = static_cast<char*>(x);
     
     // Spaces between type and pointer are OK, but be consistent.
     std::vector<char *> x;
     
    -
    -

    Vertical Whitespace

    -

    Minimize use of vertical whitespace.

    -
    - -

    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 @@ -6283,25 +5572,19 @@ useful:

    preceding. -
    -

    Exceptions to the Rules

    The coding conventions described above are mandatory. However, like all good rules, these sometimes have exceptions, which we discuss here.

    - +

    Existing Non-conformant Code

    -

    You may diverge from the rules when dealing with code that does not conform to this style guide.

    -
    - -

    If you find yourself modifying code that was written to specifications other than those presented by this @@ -6312,23 +5595,19 @@ original author or the person currently responsible for the code. Remember that consistency includes local consistency, too.

    -
    -
    + + -

    Windows Code

    -

    Windows programmers have developed their own set of coding conventions, mainly derived from the conventions in Windows headers and other Microsoft code. We want to make it easy for anyone to understand your code, so we have a single set of guidelines for everyone writing C++ on any platform.

    -
    -

    It is worth reiterating a few of the guidelines that you might forget if you are used to the prevalent Windows style:

    @@ -6372,7 +5651,7 @@ style:

    occasionally need to break on Windows:

    -
    -

    Parting Words

    Use common sense and BE CONSISTENT.

    @@ -6431,8 +5708,6 @@ to avoid this.

    more interesting. Have fun!


    - -