diff --git a/cppguide.html b/cppguide.html index 590cc9f..7f837ac 100644 --- a/cppguide.html +++ b/cppguide.html @@ -1,11 +1,11 @@ - + - + Google C++ Style Guide - - - + + +
@@ -427,10 +427,14 @@ as follows:

  1. dir2/foo2.h.
  2. +
  3. A blank line
  4. +
  5. C system files.
  6. C++ system files.
  7. +
  8. A blank line
  9. +
  10. Other libraries' .h files.
  11. @@ -439,6 +443,8 @@ as follows:

    files.
+

Note that any adjacent blank lines should be collapsed.

+

With the preferred ordering, if dir2/foo2.h omits any necessary includes, the build of dir/foo.cc @@ -455,6 +461,11 @@ directories too.

+

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

+

Within each section the includes should be ordered alphabetically. Note that older code might not conform to this rule and should be fixed when convenient.

@@ -480,8 +491,6 @@ might look like this:

#include <sys/types.h> #include <unistd.h> - -#include <hash_map> #include <vector> #include "base/basictypes.h" @@ -545,15 +554,15 @@ can continue to refer to Foo without the prefix.

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

-
namespace X {
-inline namespace Y {
+
namespace outer {
+inline namespace inner {
   void foo();
-}  // namespace Y
-}  // namespace X
+}  // namespace inner
+}  // namespace outer
 
-

The expressions X::Y::foo() and -X::foo() are interchangeable. Inline +

The expressions outer::inner::foo() and +outer::foo() are interchangeable. Inline namespaces are primarily intended for ABI compatibility across versions.

@@ -621,13 +630,13 @@ void MyClass::Foo() { DEFINE_FLAG(bool, someflag, false, "dummy flag"); -namespace a { +namespace mynamespace { using ::foo::bar; -...code for a... // Code goes against the left margin. +...code for mynamespace... // Code goes against the left margin. -} // namespace a +} // namespace mynamespace @@ -690,11 +699,11 @@ of these constructs in .h files.
-

All declarations can be given internal linkage by placing them in -unnamed namespaces, and functions and variables can be given internal linkage by +

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.

+can't be accessed from another file. If a different file declares something with +the same name, then the two entities are completely independent.

@@ -717,10 +726,9 @@ Do not use internal linkage in .h files.

Prefer placing nonmember functions in a namespace; use completely global -functions rarely. Prefer grouping functions with a namespace instead of -using a class as if it were a namespace. Static methods of a class should -generally be closely related to instances of the class or the class's static -data.

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

@@ -743,26 +751,9 @@ function not bound to a class instance. Such a function can be either a static member or a nonmember function. Nonmember functions should not depend on external variables, and should nearly always exist in a namespace. -Rather than creating classes only to group static member -functions which do not share static data, use -namespaces instead. For a header -myproject/foo_bar.h, for example, write

-
namespace myproject {
-namespace foo_bar {
-void Function1();
-void Function2();
-}  // namespace foo_bar
-}  // namespace myproject
-
-

instead of

-
namespace myproject {
-class FooBar {
- public:
-  static void Function1();
-  static void Function2();
-};
-}  // namespace myproject
-
+Do not create classes only to group static member functions; +this is no different than just giving the function names a +common prefix, and such grouping is usually unnecessary anyway.

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

Static and Global Variables

-

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

+

Objects with + +static storage duration are forbidden unless they are +trivially +destructible. Informally this means that the destructor does not do +anything, even taking member and base destructors into account. More formally it +means that the type has no user-defined or virtual destructor and that all bases +and non-static members are trivially destructible. +Static function-local variables may use dynamic initialization. +Use of dynamic initialization for static class member variables or variables at +namespace scope is discouraged, but allowed in limited circumstances; see below +for details.

+ +

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

-

Objects with static storage duration, including global -variables, static variables, static class member -variables, and function static variables, must be Plain -Old Data (POD): only ints, chars, floats, or pointers, or -arrays/structs of POD.

+
+

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 +namespace scope ("global variables"), as static data members of classes, or as +function-local variables that are declared with the static +specifier. Function-local static variables are initialized when control first +passes through their declaration; all other objects with static storage duration +are initialized as part of program start-up. All objects with static storage +duration are destroyed at program exit (which happens before unjoined threads +are terminated).

-

The order in which class constructors and initializers -for static variables are called is only partially -specified in C++ and can even change from build to build, -which can cause bugs that are difficult to find. -Therefore in addition to banning globals of class type, -we do not allow non-local static variables to be initialized -with the result of a function, unless that function (such -as getenv(), or getpid()) does not itself depend on any -other globals. However, a static POD variable within -function scope may be initialized with the result of a -function, since its initialization order is well-defined -and does not occur until control passes through its -declaration.

+

Initialization may be dynamic, which means that something +non-trivial happens during initialization. (For example, consider a constructor +that allocates memory, or a variable that is initialized with the current +process ID.) The other kind of initialization is static +initialization. The two aren't quite opposites, though: static +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.

+
-

Likewise, global and static variables are destroyed -when the program terminates, regardless of whether the -termination is by returning from main() or -by calling exit(). The order in which -destructors are called is defined to be the reverse of -the order in which the constructors were called. Since -constructor order is indeterminate, so is destructor -order. For example, at program-end time a static variable -might have been destroyed, but code still running -— perhaps in another thread -— tries to access it and fails. Or the -destructor for a static string variable -might be run prior to the destructor for another variable -that contains a reference to that string.

+
+

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.

+
-

One way to alleviate the destructor problem is to -terminate the program by calling -quick_exit() instead of exit(). -The difference is that quick_exit() does not -invoke destructors and does not invoke any handlers that -were registered by calling atexit(). If you -have a handler that needs to run when a program -terminates via quick_exit() (flushing logs, -for example), you can register it using -at_quick_exit(). (If you have a handler that -needs to run at both exit() and -quick_exit(), you need to register it in -both places.)

+
+

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 +neither is destruction (except that destruction +happens in reverse order of initialization). When one initialization refers to +another variable with static storage duration, it is possible that this causes +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.

+
-

As a result we only allow static variables to contain -POD data. This rule completely disallows -std::vector (use C arrays instead), or -string (use const char []).

- - - -

If you need a static or global -variable of a class type, consider initializing a pointer -(which will never be freed), from either your main() -function or from pthread_once(). Note that this must be a -raw pointer, not a "smart" pointer, since the smart -pointer's destructor will have the order-of-destructor -issue that we are trying to avoid.

+
+

Decision on destruction

+ +

When destructors are trivial, their execution is not subject to ordering at +all (they are effectively not "run"); otherwise we are exposed to the risk of +accessing objects after the end of their lifetime. Therefore, we only allow +objects with static storage duration if they are trivially destructible. +Fundamental types (like pointers and int) are trivially +destructible, as are arrays of trivially destructible types. Note that +variables marked with constexpr are trivially destructible.

+
const int kNum = 10;  // allowed
+
+struct X { int n; };
+const X kX[] = {{1}, {2}, {3}};  // allowed
+
+void foo() {
+  static const char* const kMessages[] = {"hello", "world"};  // allowed
+}
+
+// allowed: constexpr guarantees trivial destructor
+constexpr std::array<int, 3> kArray = {{1, 2, 3}};
+
// bad: non-trivial destructor
+const 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");
+
+void bar() {
+  // bad: non-trivial destructor
+  static std::map<int, int> kData = {{1, 0}, {2, 0}, {3, 0}};
+}
+ +

Note that references are not objects, and thus they are not subject to the +constraints on destructibility. The constraint on dynamic initialization still +applies, though. In particular, a function-local static reference of the form +static T& t = *new T; is allowed.

+ +

Decision on initialization

+ +

Initialization is a more complex topic. This is because we must not only +consider whether class constructors execute, but we must also consider the +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)
+ +

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

+ +

The concept we are looking for is called constant initialization in +the formal language of the C++ standard. It means that the initializing +expression is a constant expression, and if the object is initialized by a +constructor call, then the constructor must be specified as +constexpr, too:

+
struct Foo { constexpr Foo(int) {} };
+
+int n = 5;  // fine, 5 is a constant expression
+Foo x(2);   // fine, 2 is a constant expression and the chosen constructor is constexpr
+Foo a[] = { Foo(1), Foo(2), Foo(3) };  // fine
+ +

Constant initialization is always allowed. Constant initialization of +static storage duration variables should be marked with constexpr +where possible. Any non-local static storage +duration variable that is not so marked should be presumed to have +dynamic initialization, and reviewed very carefully.

+ +

By contrast, the following initializations are problematic:

+ +
time_t time(time_t*);      // not constexpr!
+int f();                   // not constexpr!
+struct Bar { Bar() {} };
+
+time_t m = time(nullptr);  // initializing expression not a constant expression
+Foo y(f());                // ditto
+Bar b;                     // chosen constructor Bar::Bar() not constexpr
+ +

Dynamic initialization of nonlocal variables is discouraged, and in general +it is forbidden. However, we do permit it if no aspect of the program depends +on the sequencing of this initialization with respect to all other +initializations. Under those restrictions, the ordering of the initialization +does not make an observable difference. For example:

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

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

+
+

Common patterns

+
    +
  • Global strings: if you require a global or static string constant, + consider using a simple character array, or a char pointer to the first + element of a string literal. String literals have static storage duration + already and are usually sufficient.
  • +
  • Maps, sets, and other dynamic containers: if you require a static, fixed + collection, such as a set to search against or a lookup table, you cannot + use the dynamic containers from the standard library as a static variable, + since they have non-trivial destructors. Instead, consider a simple array of + 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.
  • +
  • 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 + in this section. One simple solution is to use a plain pointer to a + dynamically allocated object and never delete it (see last item).
  • +
  • Static variables of custom types: if you require static, constant data of + 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.)
  • +
+

thread_local Variables

+ +
+

thread_local variables that aren't declared inside a function +must be initialized with a true compile-time constant. 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 = ...;
+
+

Such a variable is actually a collection of objects, so that when different +threads access it, they are actually accessing different objects. +thread_local variables are much like +static storage duration variables +in many respects. For instance, they can be declared at namespace scope, +inside functions, or as static class members, but not as ordinary class +members.

+ +

thread_local variable instances are initialized much like +static variables, except that they must be initialized separately for each +thread, rather than once at program startup. This means that +thread_local variables declared within a function are safe, but +other thread_local variables are subject to the same +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 + concurrent programming.
  • +
  • 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.
  • +
  • thread_local variables are effectively global variables, + and have all the drawbacks of global variables other than lack of + thread-safety.
  • +
  • The memory consumed by a thread_local variable scales with + the number of running threads (in the worst case), which can be quite large + in a program.
  • +
  • An ordinary class member cannot be thread_local.
  • +
  • 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 + namespace-scope thread_local by defining a function or + static method that exposes it:

+ +
Foo& MyThreadLocalFoo() {
+  thread_local Foo result = ComplicatedInitialization();
+  return result;
+}
+
+ +

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

+ + + +

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

+
+ +
+ +

Classes

Classes are the fundamental unit of code in C++. Naturally, @@ -1086,7 +1273,7 @@ your project leads to request a waiver of this rule.

Constructors that cannot be called with a single argument -should usually omit explicit. Constructors that +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};).

@@ -1097,25 +1284,32 @@ also omit explicit, in order to support copy-initialization

Copyable and Movable Types

-

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

+

A class's public API should make explicit 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 copyable type allows its objects to be initialized or assigned -from any other object of the same type, without changing the value of the source. -For user-defined types, the copy behavior is defined by the copy -constructor and the copy-assignment operator. -string is an example of a copyable type.

-

A movable type is one that can be initialized and assigned -from temporaries (all copyable types are therefore movable). +from temporaries.

+ +

A copyable type is one that can be initialized or assigned from +any other object of the same type (so is also movable by definition), with the +stipulation that the value of the source does not change. std::unique_ptr<int> is an example of a movable but not -copyable type. For user-defined types, the move behavior is defined by the move -constructor and the move-assignment operator.

+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 +movable types that are also copyable. (For int, the move and copy +operations are the same; for 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 +constructor and the copy-assignment operator. Move behavior is defined by the +move constructor and the move-assignment operator, if they exist, or by the +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.

@@ -1170,49 +1364,82 @@ encourage excessive copying, which can cause performance problems.

-

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

+

Every class's public interface should make explicit 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.

-

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

+

Specifically, a copyable class should explicitly declare the copy +operations, a move-only class should explicitly declare the move operations, +and a non-copyable/movable class should explicitly delete the copy operations. +Explicitly declaring or deleting all four copy/move operations is permitted, +but not required. If you provide a copy or move assignment operator, you +must also provide the corresponding constructor.

-
class Foo {
+
class Copyable {
  public:
-  Foo(Foo&& other) : field_(other.field) {}
-  // Bad, defines only move constructor, but not operator=.
+  Copyable(const Copyable& rhs) = default;
+  Copyable& operator=(const Copyable& rhs) = default;
 
- private:
-  Field field_;
+  // The implicit move operations are suppressed by the declarations above.
+};
+
+class MoveOnly {
+ public:
+  MoveOnly(MoveOnly&& rhs);
+  MoveOnly& operator=(MoveOnly&& rhs);
+
+  // The copy operations are implicitly deleted, but you can
+  // spell that out explicitly if you want:
+  MoveOnly(const MoveOnly&) = delete;
+  MoveOnly& operator=(const MoveOnly&) = delete;
+};
+
+class NotCopyableOrMovable {
+ public:
+  // Not copyable or movable
+  NotCopyableOrMovable(const NotCopyableOrMovable&) = delete;
+  NotCopyableOrMovable& operator=(const NotCopyableOrMovable&)
+      = delete;
+
+  // The move operations are implicitly disabled, but you can
+  // spell that out explicitly if you want:
+  NotCopyableOrMovable(NotCopyableOrMovable&&) = delete;
+  NotCopyableOrMovable& operator=(NotCopyableOrMovable&&)
+      = delete;
 };
 
-

Due to the risk of slicing, avoid providing an assignment -operator or public copy/move constructor for a class that's -intended to be derived from (and avoid deriving from a class +

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

+ +

A type should not be copyable/movable if the meaning of +copying/moving is unclear to a casual user, or if it incurs unexpected +costs. Move operations for copyable types are strictly a performance +optimization and are a potential source of bugs and complexity, so +avoid defining them unless they are significantly more efficient than +the corresponding copy operations. If your type provides copy operations, it is +recommended that you design your class so that the default implementation of +those operations is correct. Remember to review the correctness of any +defaulted operations as you would any other code.

+ +

Due to the risk of slicing, prefer to avoid providing a public assignment +operator or copy/move constructor for a class that's +intended to be derived from (and prefer to avoid deriving from a class with such members). If your base class needs to be copyable, provide a public virtual Clone() method, and a protected copy constructor that derived classes can use to implement it.

-

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

-
// MyClass is neither copyable nor movable.
-MyClass(const MyClass&) = delete;
-MyClass& operator=(const MyClass&) = delete;
-
- -

@@ -1294,9 +1521,7 @@ implementing a sub-class is spread between the base and the sub-class, it can be more difficult to understand an implementation. The sub-class cannot override functions that are not virtual, so the sub-class cannot change -implementation. The base class may also define some data -members, so that specifies physical layout of the base -class.

+implementation.

@@ -1312,23 +1537,15 @@ subclasses Foo if it can reasonably be said that Bar "is a kind of" Foo.

-

Make your destructor virtual if -necessary. If your class has virtual methods, its -destructor should be virtual.

-

Limit the use of protected to those member functions that might need to be accessed from subclasses. Note that data members should be private.

-

Explicitly annotate overrides of virtual functions -or virtual destructors with an override -or (less frequently) final specifier. -Older (pre-C++11) code will use the -virtual keyword as an inferior -alternative annotation. For clarity, use exactly one of -override, final, or -virtual when declaring an override. +

Explicitly annotate overrides of virtual functions or virtual +destructors with exactly one of an override or (less +frequently) final specifier. Do not +use virtual when declaring an override. Rationale: A function or destructor marked override or final that is not an override of a base class virtual function will @@ -1594,14 +1811,20 @@ apply to operator overloading as well.

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

+
+ +
+ +

For technical reasons, we allow data members of a test fixture class to be protected when using Google Test).

-
+ +

Declaration Order

@@ -1634,24 +1857,33 @@ Functions for more details.

Functions

-

Parameter Ordering

+ +

Output Parameters

-

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

+

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

-

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

+

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.

+ +

Parameters are either input to the function, output from the +function, or both. Input parameters are usually values or +const references, while output and input/output +parameters will be pointers to non-const.

+ +

When ordering function parameters, put all input-only +parameters before any output parameters. In particular, +do not add new parameters to the end of the function just +because they are new; place new input-only parameters before +the output parameters.

This is not a hard-and-fast rule. Parameters that are both input and output (often classes/structs) muddy the @@ -1773,7 +2005,9 @@ which overload is being called.

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

+takes const char*. However, in this case consider +std::string_view + instead.

class MyClass {
  public:
@@ -1800,13 +2034,13 @@ function.

-

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

You may overload a function when there are no semantic +differences between variants, or when the differences are +clear at the callsite.

+ +

If you are overloading a function to support variable +number of arguments of the same type, consider making it +take a std::vector so that the user can use an initializer list to specify the arguments.

@@ -1907,9 +2141,13 @@ doubt, use overloads.

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

-
template <class T, class U> auto add(T t, U u) -> decltype(t + u);
+
    template <typename T, typename U>
+    auto add(T t, U u) -> decltype(t + u);
+  
versus -
template <class T, class U> decltype(declval<T&>() + declval<U&>()) add(T t, U u);
+
    template <typename T, typename U>
+    decltype(declval<T&>() + declval<U&>()) add(T t, U u);
+  
@@ -2085,8 +2323,7 @@ do use shared ownership, prefer to use

cpplint

-

Use cpplint.py -to detect style errors.

+

Use cpplint.py to detect style errors.

@@ -2322,13 +2559,107 @@ exceptions in Google open-source projects as well. Things would probably be different if we had to do it all over again from scratch.

-

This prohibition also applies to the exception-related -features added in C++11, such as noexcept, -std::exception_ptr, and +

This prohibition also applies to the exception handling related +features added in C++11, such as +std::exception_ptr and std::nested_exception.

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 +crashes via std::terminate.

+ +

The noexcept operator performs a compile-time +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. + std::vector<T>::resize() moves rather than + copies the objects if T's move constructor is + noexcept.
  • + +
  • Specifying noexcept on a function can + trigger compiler optimizations in environments where + exceptions are enabled, e.g. compiler does not have to + generate extra code for stack-unwinding, if it knows + 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 + specifiers are correct, and hard to define what + correctness even means.
  • + +
  • It's hard, if not impossible, to undo noexcept + 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 +from within the function body then it represents a fatal error. +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 +your project leads.

+ +

Prefer unconditional noexcept if exceptions are +completely disabled (i.e. most Google C++ environments). +Otherwise, use conditional noexcept specifiers +with simple conditions, in ways that evaluate false only in +the few cases where the function could potentially throw. +The tests might include type traits check on whether the +involved operation might throw (e.g. +std::is_nothrow_move_constructible for +move-constructing objects), or on whether allocation can throw +(e.g. absl::default_allocator_is_nothrow for +standard default allocation). Note in many cases the only +possible cause for an exception is allocation failure (we +believe move constructors should not throw except due to +allocation failure), and there are many applications where it’s +appropriate to treat memory exhaustion as a fatal error rather +than an exceptional condition that your program should attempt +to recover from. Even for other +potential failures you should prioritize interface simplicity +over supporting all possible exception throwing scenarios: +instead of writing a complicated noexcept clause +that depends on whether a hash function can throw, for example, +simply document that your component doesn’t support hash +functions throwing and make it unconditionally +noexcept.

+
@@ -2380,7 +2711,7 @@ objects. Consider

bool Base::Equal(Base* other) = 0;
 bool Derived::Equal(Base* other) {
   Derived* that = dynamic_cast<Derived*>(other);
-  if (that == NULL)
+  if (that == nullptr)
     return false;
   ...
 }
@@ -2519,7 +2850,9 @@ RTTI section for guidance on the use of
 
 

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

+usages. Overload << for streaming only for types +representing values, and write only the user-visible value, not any +implementation details.

@@ -2576,12 +2909,7 @@ flawed.
  • The streams API is subtle and complex, so programmers must -develop experience with it in order to use it effectively. -However, streams were historically banned in Google code (except -for logging and diagnostics), so Google engineers tend not to -have that experience. Consequently, streams-based code is likely -to be less readable and maintainable by Googlers than code based -on more familiar abstractions.
  • +develop experience with it in order to use it effectively.
  • Resolving the many overloads of << is extremely costly for the compiler. When used pervasively in a @@ -2834,8 +3162,9 @@ choose a larger type.

    -

    C++ does not specify the sizes of its integer types. -Typically people assume that short is 16 bits, +

    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.

    @@ -2894,35 +3223,32 @@ sure to use a type that will accommodate any possible usage of your container. When in doubt, use a larger type rather than a smaller type.

    -

    Use care when converting integer types. Integer -conversions and promotions can cause non-intuitive -behavior.

    +

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

    On Unsigned Integers

    -

    Some people, including some textbook authors, -recommend using unsigned types to represent numbers that -are never negative. This is intended as a form of -self-documentation. However, in C, the advantages of such -documentation are outweighed by the real bugs it can -introduce. Consider:

    +

    Unsigned integers are good for representing bitfields and modular +arithmetic. Because of historical accident, the C++ standard also uses +unsigned integers to represent the size of containers - many members +of the standards body believe this to be a mistake, but it is +effectively impossible to fix at this point. The fact that unsigned +arithmetic doesn't model the behavior of a simple integer, but is +instead defined by the standard to model modular arithmetic (wrapping +around on overflow/underflow), means that a significant class of bugs +cannot be diagnosed by the compiler. In other cases, the defined +behavior impedes optimization.

    -
    for (unsigned int i = foo.Length()-1; i >= 0; --i) ...
    -
    - -

    This code will never terminate! Sometimes gcc will -notice this bug and warn you, but often it will not. -Equally bad bugs can occur when comparing signed and -unsigned variables. Basically, C's type-promotion scheme -causes unsigned types to behave differently than one -might expect.

    - -

    So, document that a variable is non-negative using -assertions. Don't use an unsigned -type.

    +

    That said, mixing signedness of integer types is responsible for an +equally large class of problems. The best advice we can provide: try +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.

  • @@ -2938,109 +3264,27 @@ problems of printing, comparisons, and structure alignment.

    • -

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

      - -
      -
      // printf macros for size_t, in the style of inttypes.h
      -#ifdef _LP64
      -#define __PRIS_PREFIX "z"
      -#else
      -#define __PRIS_PREFIX
      -#endif
      -
      -// Use these macros after a % in a printf format string
      -// to get correct 32/64 bit behavior, like this:
      -// size_t size = records.size();
      -// printf("%" PRIuS "\n", size);
      -
      -#define PRIdS __PRIS_PREFIX "d"
      -#define PRIxS __PRIS_PREFIX "x"
      -#define PRIuS __PRIS_PREFIX "u"
      -#define PRIXS __PRIS_PREFIX "X"
      -#define PRIoS __PRIS_PREFIX "o"
      -  
      -
      - - - - - - - - - - - - - - - - +

      Correct portable printf() conversion specifiers for + some integral typedefs rely on macro expansions that we find unpleasant to + use and impractical to require (the PRI macros from + <cinttypes>). Unless there is no reasonable alternative + 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 + std::ostream.

      - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
      TypeDO NOT useDO useNotes
      void * (or any pointer)%lx%p
      int64_t%qd, %lld%" PRId64 "
      uint64_t%qu, %llu, - %llx%" PRIu64 ", - %" PRIx64 "
      size_t%u%" PRIuS ", %" PRIxS " - C99 specifies %zu
      ptrdiff_t%d%" PRIdS " - C99 specifies %td
      - -

      Note that the PRI* macros expand to - independent strings which are concatenated by the - compiler. Hence if you are using a non-constant - format string, you need to insert the value of the - macro into the format, rather than the name. Note also - that spaces are required around the macro identifier to - separate it from the string literal. It is - still possible, as usual, to include length - specifiers, etc., after the % when using - the PRI* macros. So, e.g. - printf("x = %30" PRIuS "\n", x) would - expand on 32-bit Linux to printf("x = %30" "u" - "\n", x), which the compiler will treat as - printf("x = %30u\n", x).

      - +

      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 + size_t (z), + ptrdiff_t (t), and + maxint_t (j).

    • Remember that sizeof(void *) != @@ -3063,13 +3307,12 @@ problems of printing, comparisons, and structure alignment.

      __declspec(align()).
    • -

      Use the LL or ULL - suffixes as needed to create 64-bit constants. For - example:

      +

      Use braced-initialization as needed to create + 64-bit constants. For example:

      -
      int64_t my_value = 0x123456789LL;
      -uint64_t my_mask = 3ULL << 48;
      +
      int64_t my_value{0x123456789};
      +uint64_t my_mask{3ULL << 48};
       
    @@ -3168,30 +3411,25 @@ name (but upper case).

    0 and nullptr/NULL

    -

    Use 0 for integers, 0.0 for -reals, nullptr (or NULL) for -pointers, and '\0' for chars.

    +

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

    -

    Use 0 for integers and 0.0 -for reals. This is not controversial.

    +

    Use 0 for integers and 0.0 for reals.

    -

    For -pointers (address values), there is a choice between -0, NULL, and -nullptr. For projects that allow C++11 -features, use nullptr. For C++03 projects, -we prefer NULL because it looks like a -pointer. In fact, some C++ compilers provide special -definitions of NULL which enable them to -give useful warnings, particularly in situations where -sizeof(NULL) is not equal to -sizeof(0).

    +

    For pointers (address values), there is a choice between 0, +NULL, and nullptr. For projects that allow C++11 +features, use nullptr, as this provides type-safety.

    -

    Use '\0' for chars. This is the correct -type and also makes code more readable.

    +

    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.

    + +

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

    @@ -3241,8 +3479,8 @@ readability.

    -

    -

      + +
      • C++ type names can be long and cumbersome, especially when they involve templates or namespaces.
      • When a C++ type name is repeated within a single declaration or a @@ -3349,7 +3587,7 @@ std::vector<string> v{"foo", "bar"}; std::vector<string> v = {"foo", "bar"}; // Usable with 'new' expressions. -auto p = new vector<string>{"foo", "bar"}; +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"}}; @@ -3938,7 +4176,8 @@ guide, the following C++11 features may not be used:

        Foo f = {.field = 3}), inline assembly, __COUNTER__, __PRETTY_FUNCTION__, compound statement expressions (e.g. foo = ({ int x; Bar(&x); x }), variable-length arrays and - alloca(), and the a?:b syntax.

        + alloca(), and the "Elvis Operator" + a?:b.

    @@ -3986,6 +4225,10 @@ using Bar = Foo; using other_namespace::Foo;
    +

    In new code, using is preferable to typedef, + because it provides a more consistent syntax with the rest of C++ and works + with templates.

    +

    Like other declarations, aliases declared in a header file are part of that header's public API unless they're in a function definition, in the private portion of a class, or in an explicitly-marked internal namespace. Aliases in such areas or in .cc files are @@ -4031,32 +4274,32 @@ implementation retain some degree of freedom to change the alias.

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

    -
    namespace a {
    +
    namespace mynamespace {
     // Used to store field measurements. DataPoint may change from Bar* to some internal type.
     // Client code should treat it as an opaque pointer.
    -using DataPoint = foo::bar::Bar*;
    +using DataPoint = foo::Bar*;
     
     // A set of measurements. Just an alias for user convenience.
     using TimeSeries = std::unordered_set<DataPoint, std::hash<DataPoint>, DataPointComparator>;
    -}  // namespace a
    +}  // namespace mynamespace
     

    These aliases don't document intended use, and half of them aren't meant for client use:

    -
    namespace a {
    +
    namespace mynamespace {
     // Bad: none of these say how they should be used.
    -using DataPoint = foo::bar::Bar*;
    +using DataPoint = foo::Bar*;
     using std::unordered_set;  // Bad: just for local convenience
     using std::hash;           // Bad: just for local convenience
     typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator> TimeSeries;
    -}  // namespace a
    +}  // namespace mynamespace
     

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

    // In a .cc file
    -using std::unordered_set;
    +using foo::Bar;
     
    @@ -4091,11 +4334,17 @@ 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.

    +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 + +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.
     
    int n;                     // Meaningless.
    @@ -4104,12 +4353,20 @@ 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.
     

    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 appear in such names, prefer to +capitalize the abbreviations as single words (i.e. StartRpc(), +not StartRPC()).

    +

    Template parameters should follow the naming style for their category: type template parameters should follow the rules for type names, and non-type template @@ -4268,9 +4525,9 @@ versus a class.

    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.

    + variables, otherwise the usual variable naming rules apply.

    -

    +

    Function Names

    @@ -4282,11 +4539,7 @@ like variables.

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

    +capital letter for each new word.

    AddTableEntry()
     DeleteUrl()
    @@ -4295,8 +4548,8 @@ OpenFileOrDie()
     
     

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

    +like functions, because the fact that they're objects rather than functions +is an unimportant implementation detail.)

    Accessors and mutators (get and set functions) may be named like variables. These often correspond to actual member variables, but this is @@ -4318,7 +4571,7 @@ 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 -a directory whose basename matches the namespace name (or +a directory whose basename matches the namespace name (or in subdirectories thereof).

    @@ -4398,7 +4651,8 @@ names are actually causing a compile-time problem.

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

    +MY_MACRO_THAT_SCARES_SMALL_CHILDREN_AND_ADULTS_ALIKE. +

    @@ -4500,7 +4754,9 @@ 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.

    +author line, consider deleting the author line. +New files should usually not contain copyright notice or +author line.

    File Contents

    @@ -4619,13 +4875,7 @@ Iterator* GetIterator() const;

    However, do not be unnecessarily verbose or state the -completely obvious. Notice below that it is not necessary - to say "returns false otherwise" because this is -implied.

    - -
    // Returns true if the table cannot hold any more entries.
    -bool IsTableFull();
    -
    +completely obvious.

    When documenting function overrides, focus on the specifics of the override itself, rather than repeating @@ -4791,7 +5041,7 @@ one of the following remedies:

  • Replace large or complex nested expressions with named variables.
  • As a last resort, use comments to clarify argument meanings at the - call site.
  • + call site. Consider the following example: @@ -5135,8 +5385,8 @@ not fit on a single line as you would wrap arguments in a
    @@ -5489,10 +5739,9 @@ should be placed as shown below.

    statements should always have a default case (in the case of an enumerated value, the compiler will warn you if any values are not handled). If the default -case should never execute, simply -assert:

    +case should never execute, treat this as an error. For example: - +

    switch (var) {
    @@ -5526,8 +5775,8 @@ for (int i = 0; i < kSomeNumber; ++i) {
     
    -

    Empty loop bodies should use an empty pair of braces or continue, -but not a single semicolon.

    +

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

    while (condition) {
       // Repeat test until it returns false.
    @@ -5582,6 +5831,11 @@ char* c;
     const string& str;
     
    +

    You should do this consistently within a single +file, +so, when modifying an existing file, use the style in +that file.

    + It is allowed (if unusual) to declare multiple variables in the same declaration, but it is disallowed if any of those have pointer or reference decorations. Such declarations are easily misread. @@ -5593,11 +5847,6 @@ char * c; // Bad - spaces on both sides of * const string & str; // Bad - spaces on both sides of & -

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

    -

    Boolean Expressions

    @@ -5691,8 +5940,8 @@ will call a default constructor if available. To force the non-std::initializer_list constructor, use parentheses instead of braces.

    -
    std::vector<int> v(100, 1);  // A vector of 100 1s.
    -std::vector<int> v{100, 1};  // A vector of 100, 1.
    +
    std::vector<int> v(100, 1);  // A vector containing 100 items: All 1s.
    +std::vector<int> v{100, 1};  // A vector containing 2 items: 100 and 1.
     

    Also, the brace form prevents narrowing of integral @@ -5867,7 +6116,7 @@ void foo() { // Correct. No extra indentation within namespace.

    namespace {
     
    -  // Wrong.  Indented when it should not be.
    +  // Wrong!  Indented when it should not be.
       void foo() {
         ...
       }
    @@ -6138,7 +6387,7 @@ occasionally need to break on Windows:

    - +

    Parting Words

    Use common sense and BE CONSISTENT.