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.
#include
statement
makes it difficult for automatic tooling to discover the module
defining the symbol.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; ++
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 . -
unique_ptr
, shared_ptr
): smart
+ 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.
Bar
"is a kind of"
Limit the use of protected
to those
member functions that might need to be accessed from
subclasses. Note that data
-members should be private.
private
.
Explicitly annotate overrides of virtual functions or virtual
destructors with exactly one of an override
or (less
@@ -1629,7 +1649,7 @@ built-in operators. For example, use |
as a
bitwise- or logical-or, not as a shell-style pipe.
Define operators only on your own types. More precisely,
-define them in the same headers, .cc files, and namespaces
+define them in the same headers, .cc
files, and namespaces
as the types they operate on. That way, the operators are available
wherever the type is, minimizing the risk of multiple
definitions. If possible, avoid defining operators as templates,
@@ -1681,18 +1701,18 @@ apply to operator overloading as well.
const
) if necessary.
For technical
-reasons, we allow data members of a test fixture class defined in a .cc file to
+reasons, we allow data members of a test fixture class defined in a .cc
file to
be protected
when using
Google
Test.
-If a test fixture class is defined outside of the .cc file it is used in, for example in a .h file,
-make data members private
.
.cc
file it is used in, for example
+in a .h
file, make data members private
.
Group similar declarations together, placing public parts +
Group similar declarations together, placing public
parts
earlier.
A class definition should usually start with a @@ -1708,6 +1728,8 @@ following order:
typedef
, using
,
enum
, nested structs and classes, and friend
types)static
data membersfriend
functions)
Do not put large method definitions inline in the @@ -1812,8 +1834,9 @@ which overload is being called.
You may write a function that takes a const
std::string&
and overload it with another that
takes const char*
. However, in this case consider
-std::string_view
- instead.
std::string_view
+
+instead.
class MyClass { public: @@ -1827,7 +1850,7 @@ std::string_view 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 +
Overloading based on
@@ -2030,7 +2053,7 @@ all copies, and the object is deleted when the last bookkeeping, simplifying the code and ruling out large classes of errors. -const
or ref qualification may make utility code more usable, more efficient, or both. (See TotW 148 for more.)
const
objects, shared ownership can be a simple
and efficient alternative to deep copying.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.Friends extend, but do not break, the encapsulation
boundary of a class. In some cases this is better than
-making a member public when you want to give only one
+making a member public
when you want to give only one
other class access to it. However, most classes should
interact with other classes solely through their public
members.
static_cast<float>(double_value)
, or brace
initialization for conversion of arithmetic types like
int64_t y = int64_t{1} << 42
. Do not use
cast formats like (int)x
unless the cast is to
-void
. You may use cast formats like `T(x)` only when
-`T` is a class type.
+void
. You may use cast formats like T(x)
only when
+T
is a class type.
C++ introduced a @@ -2797,7 +2820,7 @@ many other contexts as well. In particular:
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
+ that state, e.g., by returning a non-const
reference, but that's
rare), or they can't safely be invoked concurrently.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.
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 @@ likeint16_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 fromboost/math/special_functions
boost/math/tools
boost/math/tools
boost/multi_index
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
.
__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
.
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.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.
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;+
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; +} ++
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 "_".
_
".
Examples of acceptable file names:
@@ -4202,7 +4275,7 @@ versus a class.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:
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 +-Self-describing code doesn't need a comment. The comment from -the example above would be obvious: +#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:
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 ofchar8_t
+rather thanchar
. -You shouldn't use
char16_t
and +You shouldn't use
lists like other comma-separated lists.char16_t
andchar32_t
character types, since they're for non-UTF-8 text. For similar reasons you also shouldn't usewchar_t
(unless you're writing code that @@ -4964,15 +5032,15 @@ return type: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 optionalelse if
-andelse
clauses, put one space between theif
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: +
if
,
+ else
, switch
, while
, do
,
+ or for
).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 +
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 noelse
orelse 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 entireif
-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(); } -- ++// OK - braces are optional in this case. +if (x == kFoo) return new Foo(); -
case
blocks inswitch
-statements can have curly braces or not, depending on -your preference. If you do include curly braces they -should be placed as shown below.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
ordo ... 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 inswitch
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;