From 193201734575f2568428b52aa6b9c470b5d1cdff Mon Sep 17 00:00:00 2001 From: Daniel Cheng Date: Mon, 12 Feb 2024 11:32:35 -0800 Subject: [PATCH] Update C++ style guide. - Give more explicit guidance about when angle bracket includes should be used. - Expand the guidance for disallowing const reference parameters that outlive the call to *all* references, const or mutable; instead, these parameters should be pointers. - Add a brief section about how concepts should be named There are also additional minor formatting changes or updating recommendations to prefer std over absl. --- cppguide.html | 80 +++++++++++++++++++++++++++++---------------------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/cppguide.html b/cppguide.html index 487529e..7c87799 100644 --- a/cppguide.html +++ b/cppguide.html @@ -414,6 +414,18 @@ should be included as:

#include "base/logging.h"
 
+

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

+ + +

In dir/foo.cc or dir/foo_test.cc, whose main purpose is to implement or test the stuff in @@ -425,9 +437,9 @@ as follows:

  • A blank line
  • -
  • C system headers (more precisely: headers in angle brackets with the - .h extension), e.g., <unistd.h>, - <stdlib.h>.
  • +
  • C system headers, and any other headers in angle brackets with the + .h extension, e.g., <unistd.h>, + <stdlib.h>, <Python.h>.
  • A blank line
  • @@ -663,9 +675,9 @@ namespace baz = ::foo::bar::baz;
    // Shorten access to some commonly used names (in a .h file).
     namespace librarian {
    -namespace impl {  // Internal, not part of the API.
    +namespace internal {  // Internal, not part of the API.
     namespace sidetable = ::pipeline_diagnostics::sidetable;
    -}  // namespace impl
    +}  // namespace internal
     
     inline void my_inline_function() {
       // namespace alias local to a function (or method).
    @@ -936,7 +948,7 @@ 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) {} };
    +
    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.
    @@ -944,10 +956,10 @@ 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 -or constinit

    . +or constinit. Any non-local static storage duration variable that is not so marked should be presumed to have -dynamic initialization, and reviewed very carefully. +dynamic initialization, and reviewed very carefully.

    By contrast, the following initializations are problematic:

    @@ -1017,10 +1029,8 @@ does not make an observable difference. For example:

    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 + + constinit attribute. Prefer thread_local over other ways of defining thread-local data.

    @@ -1093,13 +1103,11 @@ get a particularly hard to diagnose use-after-free.

    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 + + constinit (or constexpr, but that should be rare):

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

    thread_local variables inside a function have no initialization @@ -1177,8 +1185,7 @@ 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 -. +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 @@ -1445,8 +1452,6 @@ by making their constructors protected, by declaring their destructors protected or by giving them one or more pure virtual member functions. Prefer to avoid deriving from concrete classes.

    - -

    Structs vs. Classes

    Use a struct only for passive objects that @@ -1794,7 +1799,7 @@ improve readability, and often provide the same or better performance.

    Prefer to return by value or, failing that, return by reference. -Avoid returning a pointer unless it can be null.

    +Avoid returning a raw pointer unless it can be null.

    Parameters are either inputs to the function, outputs from the function, or both. Non-optional input parameters should usually be values @@ -1808,10 +1813,10 @@ optional outputs and optional input/output parameters.

    -Avoid defining functions that require a const reference parameter -to outlive the call, because const reference parameters bind -to temporaries. Instead, find a way to eliminate the lifetime requirement -(for example, by copying the parameter), or pass it by const +Avoid defining functions that require a reference parameter to outlive the call. +In some cases reference parameters can bind to temporaries, leading to lifetime +bugs. Instead, find a way to eliminate the lifetime requirement +(for example, by copying the parameter), or pass retained parameters by pointer and document the lifetime and non-null requirements.

    @@ -2255,10 +2260,10 @@ qualifier to methods), except as follows:

  • You may use them to define pairs of overloads, such as 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.
  • + pair of functions sometimes yields better performance, for example if the + functions sometimes don't consume the input. As always: if you're writing + more complicated code for the sake of performance, make sure you have evidence + that it actually helps.

    Friends

    @@ -2642,9 +2647,9 @@ casts when explicit type conversion is necessary. including void*. Use this only if you know what you are doing and you understand the aliasing issues. Also, consider dereferencing the pointer (without a cast) and - using absl::bit_cast to cast the resulting value. + using std::bit_cast to cast the resulting value. -
  • Use absl::bit_cast to interpret the raw bits of a +
  • Use std::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_t.
  • @@ -3243,8 +3248,8 @@ auto c = b; // c is an int auto d{42}; // d is an int, not a std::initializer_list<int>
    auto can be qualified with const, and can be - used as part of a pointer or reference type, but it can't be used as a - template argument. A rare variant of this syntax uses + used as part of a pointer or reference type, and (since C++17) as a + non-type template argument. A rare variant of this syntax uses decltype(auto) instead of auto, in which case the deduced type is the result of applying decltype @@ -4366,6 +4371,10 @@ using PropertiesMap = hash_map<UrlTableProperties *, std::string>; enum class UrlTableError { ...
    +

    Concept Names

    + +Concept names follow the same rules as type names. +

    Variable Names

    The names of variables (including function parameters) and data members are @@ -5216,7 +5225,8 @@ double d = 1248e6;

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