diff --git a/cppguide.html b/cppguide.html index a7f3224..788f63a 100644 --- a/cppguide.html +++ b/cppguide.html @@ -174,8 +174,9 @@ input.

Do not use non-standard extensions.

-
Consider portability to other environments -before using features from C++14 and C++17 in your project. +
+

Consider portability to other environments before using features +from C++14 and C++17 in your project.

Header Files

@@ -300,7 +301,7 @@ ABSL_DECLARE_FLAG(flag_in_b); user code to skip necessary recompilation when headers change. -
  • A forward declaration as opposed to an #include statement +
  • A forward declaration as opposed to an #include statement makes it difficult for automatic tooling to discover the module defining the symbol.
  • @@ -676,6 +677,15 @@ inline void my_inline_function() {
  • Do not use inline namespaces.
  • + +
  • Use namespaces with "internal" in the name to document parts of an API that + should not be mentioned by users of the API. +

    + +
    // We shouldn't use this internal name in non-absl code.
    +using ::absl::container_internal::ImplementationDetail;
    +
    +
  • @@ -745,10 +755,10 @@ its scope.

    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 -scope as possible, and as close to the first use as -possible. This makes it easier for the reader to find the +

    C++ allows you to declare variables anywhere in a function. +We encourage you to declare them in a scope as local as +possible, and as close to the first use as possible. +This makes it easier for the reader to find the declaration and see what type the variable is and what it was initialized to. In particular, initialization should be used instead of declaration and assignment, e.g.,:

    @@ -757,7 +767,17 @@ be used instead of declaration and assignment, e.g.,:

    i = f(); // Bad -- initialization separate from declaration. -
    int j = g();  // Good -- declaration has initialization.
    +
    int i = f();  // Good -- declaration has initialization.
    +
    + + +
    int jobs = NumJobs();
    +// More code...
    +f(jobs);      // Bad -- declaration separate from use.
    +
    + +
    int jobs = NumJobs();
    +f(jobs);      // Good -- declaration immediately (or closely) followed by use.
     
    std::vector<int> v;
    @@ -979,7 +999,7 @@ does not make an observable difference. For example:

    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 +
  • Smart pointers (std::unique_ptr, std::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 @@ -1180,8 +1200,8 @@ void Func(Foo f);
  • Func({42, 3.14});  // Error
     
    -This kind of code isn't technically an implicit conversion, but the -language treats it as one as far as explicit is concerned. +

    This kind of code isn't technically an implicit conversion, but the +language treats it as one as far as explicit is concerned.

    @@ -2133,12 +2156,12 @@ are a type of reference that can only bind to temporary objects. The syntax is similar to traditional reference syntax. For example, void f(std::string&& s); declares a function whose argument is an -rvalue reference to a std::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.

    +rules apply. Such a reference is called a forwarding reference.

    @@ -2850,9 +2873,9 @@ types; and definition of constants with function calls.

    -

    Prematurely marking something as constexpr may cause +

    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 +Current restrictions on what is allowed in constexpr functions and constructors may invite obscure workarounds in these definitions.

    @@ -2869,23 +2892,24 @@ enable their use with constexpr. Do not use

    Of the built-in C++ integer types, the only one used is -int. If a program needs a variable of a -different size, use a precise-width integer type from +int. If a program needs an integer type of a +different size, use an exact-width integer type from <cstdint>, such as -int16_t. If your variable represents a -value that could ever be greater than or equal to 2^31 -(2GiB), use a 64-bit type such as int64_t. +int16_t. If you have a +value that could ever be greater than or equal to 2^31, +use a 64-bit type such as int64_t. 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 precisely 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.

    +

    C++ does not specify exact sizes for the integer types +like int. Common sizes on contemporary architectures are +16 bits for short, 32 bits for int, 32 or 64 +bits for long, and 64 bits for long long, +but different platforms make different choices, in particular +for long.

    Uniformity of declaration.

    @@ -2902,9 +2926,9 @@ like int16_t, uint32_t, int64_t, etc. You should always use those in preference to short, unsigned long long and the like, when you need a guarantee -on the size of an integer. Of the C integer types, only +on the size of an integer. Of the built-in integer types, only int should be used. When appropriate, you -are welcome to use standard types like +are welcome to use standard type aliases like size_t and ptrdiff_t.

    We use int very often, for integers we @@ -3308,14 +3332,14 @@ auto i = y.Find(key);

    For local variables, you can use type deduction to make the code clearer by eliminating type information that is obvious or irrelevant, so that the reader can focus on the meaningful parts of the code:

    -
    std::unique_ptr<WidgetWithBellsAndWhistles> widget_ptr =
    +  
    std::unique_ptr<WidgetWithBellsAndWhistles> widget =
         std::make_unique<WidgetWithBellsAndWhistles>(arg1, arg2);
     absl::flat_hash_map<std::string,
                         std::unique_ptr<WidgetWithBellsAndWhistles>>::const_iterator
         it = my_map_.find(key);
     std::array<int, 6> numbers = {4, 8, 15, 16, 23, 42};
    -
    auto widget_ptr = std::make_unique<WidgetWithBellsAndWhistles>(arg1, arg2);
    +  
    auto widget = std::make_unique<WidgetWithBellsAndWhistles>(arg1, arg2);
     auto it = my_map_.find(key);
     std::array numbers = {4, 8, 15, 16, 23, 42};
    @@ -3795,7 +3819,7 @@ Currently, the following libraries are permitted:

    Special Functions from boost/math/special_functions
  • - Root Finding Functions from boost/math/tools
  • + Root Finding & Minimization Functions from boost/math/tools
  • Multi-index from boost/multi_index
  • @@ -3869,11 +3893,12 @@ guide, the following C++ features may not be used:

    Compilers support various extensions that are not part of standard C++. Such extensions include GCC's __attribute__, intrinsic functions such - as __builtin_prefetch, inline assembly, __COUNTER__, - __PRETTY_FUNCTION__, compound statement expressions (e.g., - foo = ({ int x; Bar(&x); x }), variable-length arrays and - alloca(), and the "Elvis Operator" - a?:b.

    + as __builtin_prefetch or SIMD, #pragma, inline + assembly, __COUNTER__, __PRETTY_FUNCTION__, + compound statement expressions (e.g., foo = ({ int x; Bar(&x); x + }), variable-length arrays and alloca(), and the + "Elvis + Operator" a?:b.

      @@ -3892,14 +3917,15 @@ guide, the following C++ features may not be used:

      between compilers.
    • Nonstandard extensions add to the language features that a reader must know to understand the code.
    • +
    • Nonstandard extensions require additional work to port across architectures.

    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.

    + are provided by a designated project-wide portability + header.

    Aliases

    @@ -3918,9 +3944,9 @@ using other_namespace::Foo;

    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 - implementation details (because client code can't refer to them), and are not restricted by this - rule.

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

      @@ -3979,13 +4005,60 @@ typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator&g } // namespace mynamespace
    -

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

    +

    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 ::foo::Bar;
     
    +

    Switch Statements

    + +

    If not conditional on an enumerated value, switch 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, treat this as an error. For example: + +

    switch (var) {
    +  case 0: {
    +    ...
    +    break;
    +  }
    +  case 1: {
    +    ...
    +    break;
    +  }
    +  default: {
    +    LOG(FATAL) << "Invalid value in switch statement: " << var;
    +  }
    +}
    +
    + +

    Fall-through from one case label to another must be annotated using the +[[fallthrough]]; attribute. [[fallthrough]]; should +be placed at a point of execution where a fall-through to the next case label +occurs. A common exception is consecutive case labels without intervening code, +in which case no annotation is needed.

    + +
    switch (x) {
    +  case 41:  // No annotation needed here.
    +  case 43:
    +    if (dont_be_picky) {
    +      // Use this instead of or along with annotations in comments.
    +      [[fallthrough]];
    +    } else {
    +      CloseButNoCigar();
    +      break;
    +    }
    +  case 42:
    +    DoSomethingSpecial();
    +    [[fallthrough]];
    +  default:
    +    DoSomethingGeneric();
    +    break;
    +}
    +
    +

    Inclusive Language

    In all code, including naming and comments, use inclusive language @@ -4098,7 +4171,7 @@ underscores (_) or dashes (-). Follow the convention that your project uses. If there is no consistent -local pattern to follow, prefer "_".

    +local pattern to follow, prefer "_".

    Examples of acceptable file names:

    @@ -4202,7 +4275,7 @@ versus a class.

    Constant Names

    -

    Variables declared constexpr or const, and whose value is fixed for +

    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:

    @@ -4242,10 +4315,10 @@ set_count(int count).

    Namespace Names

    -Namespace names are all lower-case, with words separated by underscores. +

    Namespace names are all lower-case, with words separated by underscores. Top-level namespace names are based on the project name . Avoid collisions -between nested namespaces and well-known top-level namespaces. +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 @@ -4319,10 +4392,9 @@ define a macro, are you? If you do, they're like this:

    Please see the description of macros; in general macros should not be used. However, if they are absolutely needed, then they should be -named with all capitals and underscores.

    +named with all capitals and underscores, and with a project-specific prefix.

    -
    #define ROUND(x) ...
    -#define PI_ROUNDED 3.0
    +
    #define MYPROJECT_ROUND(x) ...
     

    Exceptions to Naming Rules

    @@ -4383,8 +4455,7 @@ 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 -Line

    +

    Legal Notice and Author Line

    @@ -4455,7 +4526,7 @@ operation.

    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). -Private methods and functions declared in `.cc` files are not exempt. +Private methods and functions declared in .cc files are not exempt. Function comments should be written with an implied subject of This function and should start with the verb phrase; for example, "Opens the file", rather than "Open the file". In general, these comments do not @@ -4652,8 +4723,8 @@ if (std::find(v.begin(), v.end(), element) != v.end()) { }
    -Self-describing code doesn't need a comment. The comment from -the example above would be obvious: +

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

    if (!IsAlreadyProcessed(element)) {
       Process(element);
    @@ -4819,19 +4890,16 @@ ASCII.

    Hex encoding is also OK, and encouraged where it enhances readability — for example, "\xEF\xBB\xBF", or, even more simply, -u8"\uFEFF", is the Unicode zero-width -no-break space character, which would be invisible if -included in the source as straight UTF-8.

    +"\uFEFF", is the Unicode zero-width +no-break space character, which would be invisible +if included in the source as straight UTF-8.

    -

    Use the u8 prefix -to guarantee that a string literal containing -\uXXXX escape sequences is encoded as UTF-8. -Do not use it for strings containing non-ASCII characters -encoded as UTF-8, because that will produce incorrect -output if the compiler does not interpret the source file -as UTF-8.

    +

    When possible, avoid the u8 prefix. +It has significantly different semantics starting in C++20 +than in C++17, producing arrays of char8_t +rather than char. -

    You shouldn't use char16_t and +

    You shouldn't use char16_t and char32_t character types, since they're for non-UTF-8 text. For similar reasons you also shouldn't use wchar_t (unless you're writing code that @@ -4964,15 +5032,15 @@ return type:

    lists like other comma-separated lists.

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

    +ampersand (&) and the variable name.

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

    Short lambdas may be written inline as function arguments.

    -
    std::set<int> to_remove = {7, 8, 9};
    +
    absl::flat_hash_set<int> to_remove = {7, 8, 9};
     std::vector<int> digits = {3, 9, 1, 8, 4, 7, 1};
     digits.erase(std::remove_if(digits.begin(), digits.end(), [&to_remove](int i) {
    -               return to_remove.find(i) != to_remove.end();
    +               return to_remove.contains(i);
                  }),
                  digits.end());
     
    @@ -5110,174 +5178,146 @@ MyType m = { // Here, you could also break before {. interiorwrappinglist2}};
    -

    Conditionals

    + +

    Looping and branching statements

    -

    In an if statement, including its optional else if -and else clauses, put one space between the if and the -opening parenthesis, and between the closing parenthesis and the curly brace (if -any), but no spaces between the parentheses and the condition or initializer. If -the optional initializer is present, put a space or newline after the semicolon, -but not before.

    +

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

      +
    • One or more statement keywords (e.g. if, + else, switch, while, do, + or for).
    • +
    • One condition or iteration specifier, inside + parentheses.
    • +
    • One or more controlled statements, or blocks of + controlled statements.
    • +
    +For these statements: -
    if(condition) {              // Bad - space missing after IF
    -if ( condition ) {           // Bad - space between the parentheses and the condition
    -if (condition){              // Bad - space missing before {
    -if(condition){               // Doubly bad
    +
      +
    • The components of the statement should be separated by single spaces (not + line breaks).
    • +
    • Inside the condition or iteration specifier, put one space (or a line + break) between each semicolon and the next token, except if the token is a + closing parenthesis or another semicolon.
    • +
    • Inside the condition or iteration specifier, do not put a space after the + opening parenthesis or before the closing parenthesis.
    • +
    • Put any controlled statements inside blocks (i.e. use curly braces).
    • +
    • Inside the controlled blocks, put one line break immediately after the + opening brace, and one line break immediately before the closing brace.
    • +
    -if (int a = f();a == 10) { // Bad - space missing after the semicolon -
    - -

    Use curly braces for the controlled statements following -if, else if and else. Break the line -immediately after the opening brace, and immediately before the closing brace. A -subsequent else, if any, appears on the same line as the preceding -closing brace, separated by a space.

    - -
    if (condition) {                   // no spaces inside parentheses, space before brace
    -  DoOneThing();                    // two space indent
    +
    if (condition) {                   // Good - no spaces inside parentheses, space before brace.
    +  DoOneThing();                    // Good - two-space indent.
       DoAnotherThing();
    -} else if (int a = f(); a != 3) {  // closing brace on new line, else on same line
    +} else if (int a = f(); a != 3) {  // Good - closing brace on new line, else on same line.
       DoAThirdThing(a);
     } else {
       DoNothing();
     }
    +
    +// Good - the same rules apply to loops.
    +while (condition) {
    +  RepeatAThing();
    +}
    +
    +// Good - the same rules apply to loops.
    +do {
    +  RepeatAThing();
    +} while (condition);
    +
    +// Good - the same rules apply to loops.
    +for (int i = 0; i < 10; ++i) {
    +  RepeatAThing();
    +}
     
    -

    For historical reasons, we allow one exception to the above rules: if an -if statement has no else or else if -clauses, then the curly braces for the controlled statement or the line breaks -inside the curly braces may be omitted if as a result the entire if -statement appears on either a single line (in which case there is a space -between the closing parenthesis and the controlled statement) or on two lines -(in which case there is a line break after the closing parenthesis and there are -no braces). For example, the following forms are allowed under this -exception.

    +
    if(condition) {}                   // Bad - space missing after `if`.
    +else if ( condition ) {}           // Bad - space between the parentheses and the condition.
    +else if (condition){}              // Bad - space missing before `{`.
    +else if(condition){}               // Bad - multiple spaces missing.
     
    -
    if (x == kFoo) return new Foo();
    +for (int a = f();a == 10) {}       // Bad - space missing after the semicolon.
     
    -if (x == kBar)
    -  return new Bar(arg1, arg2, arg3);
    -
    -if (x == kQuz) { return new Quz(1, 2, 3); }
    -
    - -

    Use this style only when the statement is brief, and consider that -conditional statements with complex conditions or controlled statements may be -more readable with curly braces. Some -projects -require curly braces always.

    - -

    Finally, these are not permitted:

    - -
    // Bad - IF statement with ELSE is missing braces
    -if (x) DoThis();
    -else DoThat();
    -
    -// Bad - IF statement with ELSE does not have braces everywhere
    +// Bad - `if ... else` statement does not have braces everywhere.
     if (condition)
       foo;
     else {
       bar;
     }
     
    -// Bad - IF statement is too long to omit braces
    +// Bad - `if` statement too long to omit braces.
     if (condition)
       // Comment
       DoSomething();
     
    -// Bad - IF statement is too long to omit braces
    +// Bad - `if` statement too long to omit braces.
     if (condition1 &&
         condition2)
       DoSomething();
     
    -

    Loops and Switch Statements

    +

    For historical reasons, we allow one exception to the above rules: the curly +braces for the controlled statement or the line breaks inside the curly braces +may be omitted if as a result the entire statement appears on either a single +line (in which case there is a space between the closing parenthesis and the +controlled statement) or on two lines (in which case there is a line break +after the closing parenthesis and there are no braces).

    -

    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.

    +
    // OK - fits on one line.
    +if (x == kFoo) { return new Foo(); }
     
    -

    case blocks in switch -statements can have curly braces or not, depending on -your preference. If you do include curly braces they -should be placed as shown below.

    +// OK - braces are optional in this case. +if (x == kFoo) return new Foo(); -

    If not conditional on an enumerated value, switch -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, treat this as an error. For example: +// OK - condition fits on one line, body fits on another. +if (x == kBar) + Bar(arg1, arg2, arg3); +

    -

    +

    This exception does not apply to multi-keyword statements like +if ... else or do ... while.

    + +
    // Bad - `if ... else` statement is missing braces.
    +if (x) DoThis();
    +else DoThat();
    +
    +// Bad - `do ... while` statement is missing braces.
    +do DoThis();
    +while (x);
    +
    + +

    Use this style only when the statement is brief, and consider that loops and +branching statements with complex conditions or controlled statements may be +more readable with curly braces. Some +projects require curly braces always.

    + +

    case blocks in switch statements can have curly +braces or not, depending on your preference. If you do include curly braces, +they should be placed as shown below.

    -
    switch (var) {
       case 0: {  // 2 space indent
    -    ...      // 4 space indent
    -    break;
    -  }
    -  case 1: {
    -    ...
    +    Foo();   // 4 space indent
         break;
       }
       default: {
    -    assert(false);
    +    Bar();
       }
     }
     
    -
    - -

    Fall-through from one case label to -another must be annotated using the -[[fallthrough]]; attribute. -[[fallthrough]]; should be placed at a -point of execution where a fall-through to the next case -label occurs. A common exception is consecutive case -labels without intervening code, in which case no -annotation is needed.

    - -
    switch (x) {
    -  case 41:  // No annotation needed here.
    -  case 43:
    -    if (dont_be_picky) {
    -      // Use this instead of or along with annotations in comments.
    -      [[fallthrough]];
    -    } else {
    -      CloseButNoCigar();
    -      break;
    -    }
    -  case 42:
    -    DoSomethingSpecial();
    -    [[fallthrough]];
    -  default:
    -    DoSomethingGeneric();
    -    break;
    -}
    -
    - -

    Braces are optional for single-statement loops.

    - -
    for (int i = 0; i < kSomeNumber; ++i)
    -  printf("I love you\n");
    -
    -for (int i = 0; i < kSomeNumber; ++i) {
    -  printf("I take it back\n");
    -}
    -
    -

    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.
    +
    while (condition) {}  // Good - `{}` indicates no logic.
    +while (condition) {
    +  // Comments are okay, too
     }
    -for (int i = 0; i < kSomeNumber; ++i) {}  // Good - one newline is also OK.
    -while (condition) continue;  // Good - continue indicates no logic.
    +while (condition) continue;  // Good - `continue` indicates no logic.
     
    -
    while (condition);  // Bad - looks like part of do/while loop.
    +
    while (condition);  // Bad - looks like part of `do-while` loop.
     

    Pointer and Reference Expressions

    @@ -5327,9 +5367,9 @@ file. When modifying an existing file, use the style in that file.

    -It is allowed (if unusual) to declare multiple variables in the same +

    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. +reference decorations. Such declarations are easily misread.

    // Fine if helpful for readability.
     int x, y;