From 3919c347aa79e6529e738b1270cc24767b830a51 Mon Sep 17 00:00:00 2001
From: Daniel Cheng
If a source or header file refers to a symbol defined elsewhere, +the file should directly include a header file which properly intends +to provide a declaration or definition of that symbol. It should not +include header files for any other reason. +
+ +Do not rely on transitive inclusions. This allows people to remove
+no-longer-needed #include
statements from their headers without
+breaking clients. This also applies to related headers
+- foo.cc
should include bar.h
if it uses a
+symbol from it even if foo.h
+includes bar.h
.
Avoid using forward declarations where possible.
-Instead, #include
the headers you need.
A "forward declaration" is a declaration of a class, -function, or template without an associated definition.
+A "forward declaration" is a declaration of an entity + without an associated definition.
+// In a C++ source file: +class B; +void FuncInB(); +extern int variable_in_b; +ABSL_DECLARE_FLAG(flag_in_b); +
#include
that header.#include
its header file.Please see Names and Order -of Includes for rules about when to #include a header.
+Try to avoid forward declarations of entities +defined in another project.You should include all the headers that define the symbols you rely
-upon, except in the unusual case of forward
-declaration. If you rely on symbols from bar.h
,
-don't count on the fact that you included foo.h
which
-(currently) includes bar.h
: include bar.h
-yourself, unless foo.h
explicitly demonstrates its intent
-to provide you the symbols of bar.h
.
For example, the includes in
google-awesome-project/src/foo/internal/fooserver.cc
@@ -563,7 +571,7 @@ namespaces, this can add a lot of clutter.
Namespaces wrap the entire source file after
@@ -1316,11 +1324,12 @@ declaring and/or deleting the appropriate operations in the public
section of the declaration.
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.
+operations, a move-only class should explicitly declare the move operations, and +a non-copyable/movable class should explicitly delete the copy operations. A +copyable class may also declare move operations in order to support efficient +moves. 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 Copyable { public: @@ -1328,12 +1337,13 @@ must also provide the corresponding constructor. Copyable& operator=(const Copyable& other) = default; // The implicit move operations are suppressed by the declarations above. + // You may explicitly declare move operations to support efficient moves. }; class MoveOnly { public: - MoveOnly(MoveOnly&& other); - MoveOnly& operator=(MoveOnly&& other); + MoveOnly(MoveOnly&& other) = default; + MoveOnly& operator=(MoveOnly&& other) = default; // The copy operations are implicitly deleted, but you can // spell that out explicitly if you want: @@ -1709,12 +1719,13 @@ a return value and sometimes via output parameters (or in/out parameters). improve readability, and often provide the same or better performance. -- -Parameters are either input to the function, output from the +
Parameters are either inputs to the function, outputs from the function, or both. Input parameters should usually be values -or
const
references, -while required (non-nullable) output and input/output parameters should -usually be references. Generally, useabsl::optional
to represent -optional inputs, and non-const
pointers to represent +orconst
references, while non-optional output and +input/output parameters should usually be references (which cannot be null). +Generally, useabsl::optional
to represent optional by-value +inputs, and use aconst
pointer when the non-optional form would +have used a reference. Use non-const
pointers to represent optional outputs.@@ -1722,7 +1733,7 @@ Avoid defining functions that require a
@@ -2394,12 +2405,12 @@ functions throwing and make it unconditionallyconst
reference parameter to outlive the call, becauseconst
reference parameters bind to temporaries. Instead, find a way to eliminate the lifetime requirement (for example, by copying the parameter), or pass it byconst
-pointer and document the non-null requirement. +pointer and document the lifetime and non-null requirements.Run-Time Type Information (RTTI)
-Avoid using Run Time Type Information (RTTI).
+Avoid using run-time type information (RTTI).
RTTI allows a -programmer to query the C++ class of an object at run -time. This is done by use of
@@ -3126,8 +3137,8 @@ memset(&data, 0, sizeof(data)); }typeid
or +programmer to query the C++ class of an object at +run-time. This is done by use oftypeid
ordynamic_cast
.
Use type deduction only if it makes the code clearer to readers who aren't familiar with the project, or if it makes the code safer. Do not use it @@ -3300,8 +3311,7 @@ std::array numbers = {4, 8, 15, 16, 23, 42}; key type aren't relevant, but the type of the values is probably useful. In such situations, it's often possible to define local variables with explicit types that convey the relevant information: -
auto it = my_map_.find(key); -if (it != my_map_.end()) { +if (auto it = my_map_.find(key); it != my_map_.end()) { WidgetWithBellsAndWhistles& widget = *it->second; // Do stuff with `widget` }@@ -3367,7 +3377,7 @@ if (it != my_map_.end()) { As with function parameter comments, this can enable tools to detect if you get the order of the fields wrong. -Class template argument deduction
+Class Template Argument Deduction
Use class template argument deduction only with templates that have explicitly opted into supporting it.
@@ -3425,7 +3435,7 @@ array(T, U...) -> std::array<T, 1 + sizeof...(U)>;Uses of CTAD must also follow the general rules on Type deduction.
-Designated initializers
+Designated Initializers
Use designated initializers only in their C++20-compliant form.
@@ -3471,7 +3481,7 @@ fields appear in the struct definition. -Lambda expressions
+Lambda Expressions
Use lambda expressions where appropriate. Prefer explicit captures when the lambda will escape the current scope.
@@ -3625,7 +3635,7 @@ complex lambdas with default capture by value.
Avoid complicated template programming.
@@ -3639,7 +3649,7 @@ computation in the type domain.Template metaprogramming allows extremely flexible interfaces that
are type safe and high performance. Facilities like
-Google Test,
+Google Test,
std::tuple
, std::function
, and
Boost.Spirit would be impossible without it.
Do not define specializations of std::hash
.
As with Boost, some modern C++ extensions encourage coding practices that hamper @@ -4029,6 +4037,21 @@ typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator&g using ::foo::Bar; +
In all code, including naming and comments, use inclusive language +and avoid terms that other programmers might find disrespectful or offensive +(such as "master" and "slave", "blacklist" and "whitelist", or "redline"), +even if the terms also have an ostensibly neutral meaning. +Similarly, use gender-neutral language unless you're referring +to a specific person (and using their preferred pronouns). For example, +use "they"/"them"/"their" for people of unspecified gender +(even +when singular), and "it"/"its" for software, computers, and other +things that aren't people.
+ + +The most important consistency rules are those that govern @@ -4270,8 +4293,8 @@ set_count(int count).
// Iterates over the contents of a GargantuanTable. // Example: -// GargantuanTableIterator* iter = table->NewIterator(); +// std::unique_ptr<GargantuanTableIterator> iter = table->NewIterator(); // for (iter->Seek("foo"); !iter->done(); iter->Next()) { // process(iter->key(), iter->value()); // } -// delete iter; class GargantuanTableIterator { ... }; @@ -4494,7 +4516,9 @@ left to comments in the function definition. declaration:
Here is an example:
-// Returns an iterator for this table. It is the client's -// responsibility to delete the iterator when it is done with it, -// and it must not use the iterator once the GargantuanTable object -// on which the iterator was created has been deleted. -// -// The iterator is initially positioned at the beginning of the table. +// Returns an iterator for this table, positioned at the first entry +// lexically greater than or equal to `start_word`. If there is no +// such entry, returns a null pointer. The client must not use the +// iterator after the underlying GargantuanTable has been destroyed. // // This method is equivalent to: -// Iterator* iter = table->NewIterator(); -// iter->Seek(""); +// std::unique_ptr<Iterator> iter = table->NewIterator(); +// iter->Seek(start_word); // return iter; -// If you are going to immediately seek to another place in the -// returned iterator, it will be faster to use NewIterator() -// and avoid the extra seek. -Iterator* GetIterator() const; +std::unique_ptr<Iterator> GetIterator(absl::string_view start_word) const;However, do not be unnecessarily verbose or state the @@ -4699,8 +4718,7 @@ the code does what it does, or make the code self describing.
Compare this:// Find the element in the vector. <-- Bad: obvious! -auto iter = std::find(v.begin(), v.end(), element); -if (iter != v.end()) { +if (std::find(v.begin(), v.end(), element) != v.end()) { Process(element); }@@ -4708,8 +4726,7 @@ if (iter != v.end()) { To this:// Process "element" unless it was already processed. -auto iter = std::find(v.begin(), v.end(), element); -if (iter != v.end()) { +if (std::find(v.begin(), v.end(), element) != v.end()) { Process(element); }@@ -5018,10 +5035,10 @@ ampersand (&) and the variable name. auto x_plus_n = [&x](int n) -> int { return x + n; }
Short lambdas may be written inline as function arguments.
-std::set<int> blacklist = {7, 8, 9}; +std::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(), [&blacklist](int i) { - return blacklist.find(i) != blacklist.end(); +digits.erase(std::remove_if(digits.begin(), digits.end(), [&to_remove](int i) { + return to_remove.find(i) != to_remove.end(); }), digits.end());@@ -5124,8 +5141,8 @@ my_widget.Transform(x1, x2, x3,Braced Initializer List Format
-Format a braced initializer list -exactly like you would format a function call in its place.
+Format a braced initializer list exactly like you would format a function +call in its place.
If the braced list follows a name (e.g., a type or variable name), format as if the
{}
were the @@ -5146,7 +5163,7 @@ SomeType variable{ {"assume a zero-length name before {"}, SomeOtherType{ "Very long string requiring the surrounding breaks.", - some, other values}, + some, other, values}, SomeOtherType{"Slightly shorter string", some, other, values}}; SomeType variable{ @@ -5161,10 +5178,11 @@ MyType m = { // Here, you could also break before {.Conditionals
-The
+if
andelse
keywords belong on separate lines. - There should be a space between theif
and the open parenthesis, - and between the close parenthesis and the curly brace (if any), but no space - between the parentheses and the condition.Each of
if
,else
, andelse if
+ belong on separate lines. There should be a space between + theif
and the open parenthesis, and between the close + parenthesis and the curly brace (if any), but no space between the + parentheses and the condition.if (condition) { // no spaces inside parentheses ... // 2 space indent. @@ -5219,8 +5237,9 @@ if (condition) {However, if one part of an -
+if
-else
statement uses curly -braces, the other part must too:if
-else
or an +if
-else if
-else
statement uses curly +braces, the other part(s) must, too:// Not allowed - curly on IF but not ELSE if (condition) { @@ -5236,10 +5255,12 @@ else { }-// Curly braces around both IF and ELSE required because +// Curly braces around IF, ELSE IF, and ELSE required because // one of the clauses used braces. if (condition) { foo; +} else if (other_condition) { + frob; } else { bar; } @@ -5360,8 +5381,8 @@ x = r->y;*
or&
.
When declaring a pointer variable or argument, you may -place the asterisk adjacent to either the type or to the +
When declaring a pointer or reference variable or argument, you may +place the asterisk/ampersand adjacent to either the type or the variable name:
// These are fine, space preceding. @@ -5385,6 +5406,7 @@ reference decorations. Such declarations are easily misread. int x, y;
int x, *y; // Disallowed - no & or * in multiple declaration +int* x, *y; // Disallowed - no & or * in multiple declaration; inconsistent spacing char * c; // Bad - spaces on both sides of * const std::string & str; // Bad - spaces on both sides of &@@ -5440,9 +5462,6 @@ return(result); // return is not a function!
Your choice of =
, ()
, or
-{}
.
You may choose between =
,
()
, and {}
; the following are
all correct: