From c6f57a913e0e178b8ae51364509d1f684c6d4462 Mon Sep 17 00:00:00 2001
From: Daniel Cheng
The goal of this guide is to manage this complexity by describing in detail the dos and don'ts of writing C++ code. These rules exist to -keep the code base manageable while still allowing +keep the codebase manageable while still allowing coders to use C++ language features productively.
Style, also known as readability, is what we call
@@ -63,10 +63,10 @@ must be large enough to justify asking all of our engineers to
remember it. The benefit is measured relative to the codebase we would
get without the rule, so a rule against a very harmful practice may
still have a small benefit if people are unlikely to do it
-anyway. This principle mostly explains the rules we don’t have, rather
+anyway. This principle mostly explains the rules we don't have, rather
than the rules we do: for example, goto contravenes many
of the following principles, but is already vanishingly rare, so the Style
-Guide doesn’t discuss it.
+Guide doesn't discuss it.
foo should have the following
guard:
-#ifndef FOO_BAR_BAZ_H_ +#ifndef FOO_BAR_BAZ_H_ #define FOO_BAR_BAZ_H_ ... @@ -275,7 +275,7 @@ includesbar.h.A "forward declaration" is a declaration of an entity without an associated definition.
-// In a C++ source file: +// In a C++ source file: class B; void FuncInB(); extern int variable_in_b; @@ -319,7 +319,7 @@ ABSL_DECLARE_FLAG(flag_in_b); Replacing an#includewith a forward declaration can silently change the meaning of code: -// b.h: +// b.h: struct B {}; struct D : B {}; @@ -455,7 +455,7 @@ directory without use of UNIX directory aliasesgoogle-awesome-project/src/base/logging.hshould be included as: -#include "base/logging.h" +#include "base/logging.h"Headers should only be included using an angle-bracketed path if the library @@ -463,11 +463,11 @@ requires you to do so. In particular, the following headers require angle brackets:
<stdlib.h>
+<stdlib.h>
and <string>).<unistd.h>
+<unistd.h>
and <windows.h>).<Python.h>).<Python.h>).In dir/foo.cc or
@@ -535,7 +535,7 @@ this rule and should be fixed when convenient.
google-awesome-project/src/foo/internal/fooserver.cc
might look like this:
-#include "foo/server/fooserver.h" +#include "foo/server/fooserver.h" #include <sys/types.h> #include <unistd.h> @@ -555,13 +555,11 @@ conditional includes. Such code can put conditional includes after other includes. Of course, keep your system-specific code small and localized. Example: -#include "foo/public/fooserver.h" +#include "foo/public/fooserver.h" -#include "base/port.h" // For LANG_CXX11. - -#ifdef LANG_CXX11 -#include <initializer_list> -#endif // LANG_CXX11 +#ifdef _WIN32 +#include <windows.h> +#endif // _WIN32Scoping
@@ -640,7 +638,7 @@ namespaces, this can add a lot of clutter. gflags definitions/declarations and forward declarations of classes from other namespaces. -// In the .h file +// In the .h file namespace mynamespace { // All declarations are within the namespace scope. @@ -654,7 +652,7 @@ class MyClass { } // namespace mynamespace-// In the .cc file +// In the .cc file namespace mynamespace { // Definition of functions is within scope of the namespace. @@ -668,7 +666,7 @@ void MyClass::Foo() {More complex
-.ccfiles might have additional details, like flags or using-declarations.#include "a.h" +#include "a.h" ABSL_FLAG(bool, someflag, false, "a flag"); @@ -710,25 +708,29 @@ using namespace foo;
Do not use Namespace aliases at namespace scope in header files except in explicitly marked internal-only namespaces, because anything imported into a namespace - in a header file becomes part of the public - API exported by that file.
+ in a header file becomes part of the public API exported by that file. + Namespace aliases can be used when those conditions don't apply, but + they must have appropriate names. -// Shorten access to some commonly used names in .cc files. -namespace baz = ::foo::bar::baz; -- -
// Shorten access to some commonly used names (in a .h file). +// In a .h file, an alias must not be a separate API, or must be hidden in an +// implementation detail. namespace librarian { + namespace internal { // Internal, not part of the API. namespace sidetable = ::pipeline_diagnostics::sidetable; } // namespace internal inline void my_inline_function() { - // namespace alias local to a function (or method). + // Local to a function. namespace baz = ::foo::bar::baz; ... } + } // namespace librarian ++ +// Remove uninteresting parts of some commonly used names in .cc files. +namespace sidetable = ::pipeline_diagnostics::sidetable;
Note that there is still a risk of collision between libraries within a
nested internal namespace, so give each library within a
namespace a unique internal namespace by adding the library's
- filename. E.g. gshoe/widget.h would use
+ filename. For example, gshoe/widget.h would use
gshoe::internal_widget as opposed to just
gshoe::internal.
.h files.
Format unnamed namespaces like named namespaces. In the terminating comment, leave the namespace name empty:
-namespace {
+namespace {
...
} // namespace
@@ -834,7 +836,7 @@ be used instead of declaration and assignment, e.g.,:
i = f(); // Bad -- initialization separate from declaration.
-int i = f(); // Good -- declaration has initialization. +-int i = f(); // Good -- declaration has initialization.@@ -843,7 +845,7 @@ i = f(); // Bad -- initialization separate from declaration. f(jobs); // Bad -- declaration separate from use.
int jobs = NumJobs(); +-int jobs = NumJobs(); f(jobs); // Good -- declaration immediately (or closely) followed by use.@@ -852,15 +854,15 @@ v.push_back(1); // Prefer initializing using brace initialization. v.push_back(2);
std::vector<int> v = {1, 2}; // Good -- v starts initialized.
+std::vector<int> v = {1, 2}; // Good -- v starts initialized.
Variables needed for if, while
and for statements should normally be declared
within those statements, so that such variables are confined
-to those scopes. E.g.:
+to those scopes. For example:
-while (const char* p = strchr(str, '/')) str = p + 1;
+while (const char* p = strchr(str, '/')) str = p + 1;
There is one caveat: if the variable is an object, its
@@ -878,7 +880,7 @@ for (int i = 0; i < 1000000; ++i) {
It may be more efficient to declare such a variable
used in a loop outside that loop:
-Foo f; // My ctor and dtor get called once each.
+Foo f; // My ctor and dtor get called once each.
for (int i = 0; i < 1000000; ++i) {
f.DoSomething(i);
}
@@ -952,7 +954,7 @@ 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
+const int kNum = 10; // Allowed
struct X { int n; };
const X kX[] = {{1}, {2}, {3}}; // Allowed
@@ -1029,7 +1031,7 @@ 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
+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).
@@ -1088,7 +1090,7 @@ attribute. Prefer
Variables can be declared with the
thread_local specifier:
-thread_local Foo foo = ...;
+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.
@@ -1158,7 +1160,7 @@ get a particularly hard to diagnose use-after-free.
constinit
(or constexpr, but that should be rare):
- constinit thread_local Foo foo = ...;
+ constinit thread_local Foo foo = ...;
thread_local variables inside a function have no initialization
@@ -1167,7 +1169,7 @@ get a particularly hard to diagnose use-after-free.
namespace-scope thread_local by defining a function or
static method that exposes it:
-Foo& MyThreadLocalFoo() {
+Foo& MyThreadLocalFoo() {
thread_local Foo result = ComplicatedInitialization();
return result;
}
@@ -1272,7 +1274,7 @@ or a conversion operator, to ensure that it can only be
used when the destination type is explicit at the point of use,
e.g., with a cast. This applies not only to implicit conversions, but to
list initialization syntax:
-class Foo {
+class Foo {
explicit Foo(int x, double y);
...
};
@@ -1440,7 +1442,7 @@ 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 {
+class Copyable {
public:
Copyable(const Copyable& other) = default;
Copyable& operator=(const Copyable& other) = default;
@@ -1682,7 +1684,7 @@ creating objects of user-defined types.
Do not put large method definitions inline in the class definition. Usually, only trivial or performance-critical, and very short, methods may be -defined inline. See Inline -Functions for more details.
+defined inline. See Defining +Functions in Header Files for more details.const char*. However, in this case consider
instead.
-class MyClass {
+class MyClass {
public:
void Analyze(const std::string &text);
void Analyze(const char *text, size_t textlen);
@@ -1952,9 +1954,14 @@ function.
between variants. These overloads may vary in types, qualifiers, or
argument count. However, a reader of such a call must not need to know
which member of the overload set is chosen, only that something
-from the set is being called. If you can document all entries in the
-overload set with a single comment in the header, that is a good sign
-that it is a well-designed overload set.
+from the set is being called.
+
+To reflect this unified design, prefer a single, comprehensive "umbrella"
+comment that documents the entire overload set and is placed before the first
+declaration.
+
+Where a reader might have difficulty connecting the umbrella
+comment to a specific overload, it's okay to have a comment for specific overloads.
Default Arguments
@@ -2014,13 +2021,13 @@ doubt, use overloads.
C++ allows two different forms of function declarations. In the older
form, the return type appears before the function name. For example:
-int foo(int x);
+int foo(int x);
The newer form uses the auto
keyword before the function name and a trailing return type after
the argument list. For example, the declaration above could
equivalently be written:
-auto foo(int x) -> int;
+auto foo(int x) -> int;
The trailing return type is in the function's scope. This doesn't
make a difference for a simple case like int but it matters
@@ -2038,11 +2045,11 @@ 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 <typename T, typename U>
+ template <typename T, typename U>
auto add(T t, U u) -> decltype(t + u);
versus
- template <typename T, typename U>
+ template <typename T, typename U>
decltype(declval<T&>() + declval<U&>()) add(T t, U u);
@@ -2050,7 +2057,7 @@ doubt, use overloads.
Trailing return type syntax is relatively new and it has no
analogue in C++-like languages such as C and Java, so some readers may
find it unfamiliar.
-Existing code bases have an enormous number of function
+
Existing codebases have an enormous number of function
declarations that aren't going to get changed to use the new syntax,
so the realistic choices are using the old syntax only or using a mixture
of the two. Using a single version is better for uniformity of style.
@@ -2187,7 +2194,7 @@ or passing a pointer or reference without transferring
ownership. Prefer to use std::unique_ptr to
make ownership transfer explicit. For example:
-std::unique_ptr<Foo> FooFactory();
+std::unique_ptr<Foo> FooFactory();
void FooConsumer(std::unique_ptr<Foo> ptr);
@@ -2222,7 +2229,7 @@ tool.
how to run cpplint.py from their project
tools. If the project you are contributing to does not,
you can download
-
+
cpplint.py separately.
@@ -2270,7 +2277,7 @@ rules apply. Such a reference is called a forwarding reference.
std::unique_ptr.
friend is to have a
Foo so that it can construct the inner state
of Foo correctly, without exposing this
state to the world. In some cases it may be useful to
-make a unittest class a friend of the class it tests.
+make a unit test class a friend of the class it tests.
Friends extend, but do not break, the encapsulation
boundary of a class. In some cases this is better than
@@ -2523,7 +2530,7 @@ move-constructing objects), or on whether allocation can throw
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
+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
@@ -2531,7 +2538,7 @@ 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
+simply document that your component doesn't support hash
functions throwing and make it unconditionally
noexcept.
RTTI is useful when considering multiple abstract objects. Consider
-bool Base::Equal(Base* other) = 0;
+bool Base::Equal(Base* other) = 0;
bool Derived::Equal(Base* other) {
Derived* that = dynamic_cast<Derived*>(other);
if (that == nullptr)
@@ -2585,7 +2592,7 @@ must be examined when making further changes.
RTTI has legitimate uses but is prone to abuse, so you
must be careful when using it. You may use it freely in
-unittests, but avoid it when possible in other code. In
+unit tests, but avoid it when possible in other code. In
particular, think twice before using RTTI in new code. If
you find yourself needing to write code that behaves
differently based on the class of an object, consider one
@@ -2671,8 +2678,8 @@ casts when explicit type conversion is necessary.
will not compile if conversion can result in information loss. The
syntax is also concise.
std::string(some_cord) to
+ std::string(some_cord) to
static_cast<std::string>(some_cord).absl::implicit_cast
@@ -2775,7 +2782,7 @@ develop experience with it in order to use it effectively.<< is
extremely costly for the compiler. When used pervasively in a
-large code base, it can consume as much as 20% of the parsing
+large codebase, it can consume as much as 20% of the parsing
and semantic analysis time.In APIs, use const whenever it makes sense.
constexpr is a better choice for some uses of
-const.
const.
Declared variables and parameters can be preceded
@@ -3015,7 +3022,7 @@ The standard library header <stdint.h> defines types
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
+long long, and the like, when you need a guarantee
on the size of an integer. Prefer to omit the std::
prefix for these types, as the extra 5 characters do
not merit the added clutter. Of the built-in integer types, only
@@ -3114,7 +3121,7 @@ single processor.
int64_t my_value{0x123456789};
+int64_t my_value{0x123456789};
uint64_t my_mask{uint64_t{3} << 48};
MyStruct data; +MyStruct data; memset(&data, 0, sizeof(data));memset(&data, 0, sizeof(MyStruct));-if (raw_size < sizeof(int)) { +if (raw_size < sizeof(int)) { LOG(ERROR) << "compressed record not big enough for count: " << raw_size; return false; } @@ -3300,7 +3307,7 @@ auto d{42}; // d is an int, not a std::initializer_list<int> rather than by an explicitauto. Confusingly, trailing return type syntax for functions also usesautoin the return-type position, but that doesn't - rely on type deduction; it's just an alternate syntax for an explicit + rely on type deduction; it's just an alternative syntax for an explicit return type.
Do not use decltype(auto) if a simpler option will work,
- because it's a fairly obscure feature, so it has a high cost in code
+
Do not use decltype(auto) if a simpler option will work;
+ because it's a fairly obscure feature, it has a high cost in code
clarity.
auto [/*field_name1=*/bound_name1, /*field_name2=*/bound_name2] = ...+
auto [/*field_name1=*/bound_name1, /*field_name2=*/bound_name2] = ...
As with function parameter comments, this can enable tools to detect if you get the order of the fields wrong.
@@ -3603,7 +3610,7 @@ when the lambda will escape the current scope. function objects. They're often useful when passing functions as arguments. For example: -std::sort(v.begin(), v.end(), [](int x, int y) {
+std::sort(v.begin(), v.end(), [](int x, int y) {
return Weight(x) < Weight(y);
});
@@ -3613,7 +3620,7 @@ explicitly by name, or implicitly using a default capture. Explicit captures
require each variable to be listed, as
either a value or reference capture:
-int weight = 3;
+int weight = 3;
int sum = 0;
// Captures `weight` by value and `sum` by reference.
std::for_each(v.begin(), v.end(), [weight, &sum](int x) {
@@ -3625,7 +3632,7 @@ std::for_each(v.begin(), v.end(), [weight, &sum](int x) {
Default captures implicitly capture any variable referenced in the
lambda body, including this if any members are used:
-const std::vector<int> lookup_table = ...;
+const std::vector<int> lookup_table = ...;
std::vector<int> indices = ...;
// Captures `lookup_table` by reference, sorts `indices` by the value
// of the associated element in `lookup_table`.
@@ -3637,7 +3644,7 @@ std::sort(indices.begin(), indices.end(), [&](int a, int b) {
A variable capture can also have an explicit initializer, which can
be used for capturing move-only variables by value, or for other situations
not handled by ordinary reference or value captures:
- std::unique_ptr<Foo> foo = ...;
+ std::unique_ptr<Foo> foo = ...;
[foo = std::move(foo)] () {
...
}
@@ -3717,7 +3724,7 @@ For example, instead of:
// and the enclosing object could have been destroyed.
prefer to write:
-{
+{
Foo foo;
...
executor->Schedule([&foo] { Frobnicate(foo); })
@@ -3800,7 +3807,7 @@ over a large number of uses.
complicated template techniques; think about whether the average
member of your team will be able to understand your code well enough
to maintain it after you switch to another project, or whether a
-non-C++ programmer or someone casually browsing the code base will be
+non-C++ programmer or someone casually browsing the codebase will be
able to understand the error messages or trace the flow of a function
they want to call. If you're using recursive template instantiations
or type lists or metafunctions or expression templates, or relying on
@@ -3940,23 +3947,68 @@ and import.
Modules are a big shift in how C++ is written and compiled, and we
are still assessing how they may fit into Google's C++ ecosystem in
the future. Furthermore, they are not currently well-supported by our
-build-systems, compilers, and other tooling, and need further
-exploration as to the best-practices when writing and using them.
+build systems, compilers, and other tooling, and need further
+exploration as to the best practices when writing and using them.
Coroutines
-Do not use coroutines (yet).
-Do not include the <coroutine> header,
-or use the co_await, co_yield,
-or co_return keywords.
+Only use C++20 coroutines via libraries that have been
+ approved by your project leads.
-NOTE: this ban is expected to be temporary, while further
-guidance is being developed.
+
+C++20 introduced
+coroutines:
+functions that can suspend and resume
+executing later. They are especially convenient for asynchronous
+programming, where they can provide substantial improvements over
+traditional callback-based frameworks.
-
+Unlike most other programming languages (Kotlin, Rust, TypeScript, etc.),
+C++ does not provide a concrete implementation of coroutines.
+Instead, it requires users to implement their own awaitable type (using a
+
+ promise type) which determines coroutine parameter types, how coroutines
+are executed, and allows running user-defined code during different stages
+of their execution.
+
+
+
In summary, designing a high-quality and interoperable coroutine library +requires a large amount of difficult work, careful thought, and extensive +documentation.
+ + + + + +Use only coroutine libraries that have been approved for + project-wide use by your project leads. Do not roll your own promise or + awaitable types.
As with Boost, some modern C++ library functionality encourages coding practices that hamper -readability—for example by removing +readability — for example by removing checked redundancy (such as type names) that may be helpful to readers, or by encouraging template metaprogramming. Other extensions duplicate functionality @@ -4126,7 +4178,7 @@ and conversion costs.
There are several ways to create names that are aliases of other entities:
-using Bar = Foo;
+using Bar = Foo;
typedef Foo Bar; // But prefer `using` in C++ code.
using ::other_namespace::Foo;
using enum MyEnumType; // Creates aliases for all enumerators in MyEnumType.
@@ -4176,11 +4228,11 @@ using enum MyEnumType; // Creates aliases for all enumerators in MyEnumType.
changes difficult.
Don't put namespace aliases in your public API. (See also Namespaces). +
Don't put namespace aliases in your public API. (See also Namespaces.)
For example, these aliases document how they are intended to be used in client code:
-namespace mynamespace {
+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*;
@@ -4218,9 +4270,9 @@ typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator&g
However, local convenience aliases are fine in function definitions, private
- sections of classes, explicitly marked internal namespaces, and in .cc files:
+ sections of classes, explicitly-marked internal namespaces, and in .cc files:
-// In a .cc file
+// In a .cc file
using ::foo::Bar;
@@ -4231,7 +4283,7 @@ 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) {
+switch (var) {
case 0: {
...
break;
@@ -4252,7 +4304,7 @@ 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) {
+switch (x) {
case 41: // No annotation needed here.
case 43:
if (dont_be_picky) {
@@ -4340,8 +4392,8 @@ parameter.
"vocabulary" names are reused so widely that they are always in context. These
names tend to be short or even abbreviated and their full meaning comes from
explicit long-form documentation rather than from just comments on their
-definition and the words within the names. E.g. absl::Status has a
-dedicated
+definition and the words within the names. For example, absl::Status
+has a dedicated
page
in a devguide,
@@ -4350,7 +4402,7 @@ often, but if you do, get
additional design review to make sure the chosen names work well when
used widely.
-class MyClass {
+class MyClass {
public:
int CountFooErrors(const std::vector<Foo>& foos) {
int n = 0; // Clear meaning given limited scope and context
@@ -4435,7 +4487,7 @@ enums, and type template parameters — have the same naming convention.
Type names should start with a capital letter and have a capital letter
for each new word. No underscores. For example:
-// classes and structs
+// classes and structs
class UrlTable { ...
class UrlTableTester { ...
struct UrlTableProperties { ...
@@ -4466,7 +4518,7 @@ Concept names follow the same rules as type names.
For example:
-std::string table_name; // OK - snake_case.
+std::string table_name; // OK - snake_case.
std::string tableName; // Bad - mixed case.
@@ -4480,7 +4532,7 @@ trailing underscore. The exception to this is static constant
class members, which should follow the rules for
naming constants.
-class TableInfo {
+class TableInfo {
public:
...
static const int kTableVersion = 3; // OK - constant naming.
@@ -4498,7 +4550,7 @@ class members, which should follow the rules for
are named like ordinary nonmember variables. They do not have
the trailing underscores that data members in classes have.
-struct UrlTableProperties {
+struct UrlTableProperties {
std::string name;
int num_entries;
static Pool<UrlTableProperties>* pool;
@@ -4517,7 +4569,7 @@ 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:
-const int kDaysInAWeek = 7;
+const int kDaysInAWeek = 7;
const int kAndroid8_0_0 = 24; // Android 8.0.0
@@ -4528,7 +4580,7 @@ class data members and those in templates where different instantiations of the
may have different values. This convention is optional for variables of other storage classes,
e.g., automatic variables; otherwise the usual variable naming rules apply. For example:
-void ComputeFoo(absl::string_view suffix) {
+void ComputeFoo(absl::string_view suffix) {
// Either of these is acceptable.
const absl::string_view kPrefix = "prefix";
const absl::string_view prefix = "prefix";
@@ -4545,26 +4597,23 @@ e.g., automatic variables; otherwise the usual variable naming rules apply. For
Function Names
-Regular functions have mixed case; accessors and mutators may be named
-like variables.
+Ordinarily, functions follow PascalCase:
+start with a capital letter and have a capital letter for each new word.
-Ordinarily, functions should start with a capital letter and have a
-capital letter for each new word.
-
-AddTableEntry()
+AddTableEntry()
DeleteUrl()
OpenFileOrDie()
-(The same naming rule applies to class- and namespace-scope
+
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.)
+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
-not required. For example, int count() and void
-set_count(int count).
+Accessors and mutators (get and set functions) may be named like variables,
+in snake_case. These often correspond to actual member variables,
+but this is not required. For example, int count() and
+void set_count(int count).
Namespace Names
@@ -4594,7 +4643,7 @@ namespaces do not protect from collisions with names in other namespaces
-enum class UrlTableError {
+enum class UrlTableError {
kOk = 0,
kOutOfMemory,
kMalformedInput,
@@ -4636,7 +4685,7 @@ 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, and with a project-specific prefix.
-#define MYPROJECT_ROUND(x) ...
+#define MYPROJECT_ROUND(x) ...
Aliases
@@ -4731,7 +4780,7 @@ author line.
accompanying comment that describes what it is for and how it should
be used.
-// Iterates over the contents of a GargantuanTable.
+// Iterates over the contents of a GargantuanTable.
// Example:
// std::unique_ptr<GargantuanTableIterator> iter = table->NewIterator();
// for (iter->Seek("foo"); !iter->done(); iter->Next()) {
@@ -4795,7 +4844,7 @@ declaration:
if it is.
Here is an example:
-// Returns an iterator for this table, positioned at the first entry +// 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. @@ -4872,7 +4921,7 @@ num_events_;), no comment is needed. of sentinel values, such as nullptr or -1, when they are not obvious. For example: -private: +private: // Used to bounds-check table accesses. -1 means // that we don't yet know how many entries the table has. int num_total_entries_; @@ -4884,7 +4933,7 @@ obvious. For example: are, what they are used for, and (if unclear) why they need to be global. For example: -// The total number of test cases that we run through in this regression test. +// The total number of test cases that we run through in this regression test. const int kNumTestCases = 6;@@ -4938,7 +4987,7 @@ const DecimalNumber product = CalculateProduct(values, 7, false, nullptr);versus:
-ProductOptions options; +ProductOptions options; options.set_precision_decimals(7); options.set_use_cache(ProductOptions::kDontUseCache); const DecimalNumber product = @@ -4949,8 +4998,8 @@ const DecimalNumber product =Do not state the obvious. In particular, don't literally describe what code does, unless the behavior is nonobvious to a reader who understands -C++ well. Instead, provide higher level comments that describe why -the code does what it does, or make the code self describing.
+C++ well. Instead, provide higher-level comments that describe why +the code does what it does, or make the code self-describing. Compare this: @@ -4962,7 +5011,7 @@ if (std::find(v.begin(), v.end(), element) != v.end()) { To this: -// Process "element" unless it was already processed. +// Process "element" unless it was already processed. if (std::find(v.begin(), v.end(), element) != v.end()) { Process(element); } @@ -4971,7 +5020,7 @@ 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)) { +if (!IsAlreadyProcessed(element)) { Process(element); }@@ -5002,23 +5051,18 @@ goal.Use
-TODOcomments for code that is temporary, a short-term solution, or good-enough but not perfect.
TODOs should include the string -TODOin all caps, followed by the +-bug ID, name, e-mail address, or other -identifier ++- -
TODOs should include the string +TODOin all caps, followed by the bug ID, name, e-mail address, or other identifier of the person or issue with the best context about the problem referenced by theTODO. --// TODO: bug 12345678 - Remove this after the 2047q4 compatibility window expires. +// TODO: bug 12345678 - Remove this after the 2047q4 compatibility window expires. // TODO: example.com/my-design-doc - Manually fix up this code the next time it's touched. // TODO(bug 12345678): Update this list after the Foo service is turned down. // TODO(John): Use a "\*" here for concatenation operator.-If your
+TODOis of the form "At a future date do something" make sure that you either include a @@ -5026,6 +5070,8 @@ very specific date ("Fix by November 2005") or a very specific event ("Remove this code when all clients can handle XML responses.").Formatting
Coding style and formatting are pretty arbitrary, but a @@ -5090,8 +5136,8 @@ can easily show longer lines.
Functions look like this:
-ReturnType ClassName::FunctionName(Type par_name1, Type par_name2) {
+ReturnType ClassName::FunctionName(Type par_name1, Type par_name2) {
DoSomething();
...
}
@@ -5174,7 +5220,7 @@ not fit on a single line as you would wrap arguments in a
If you have too much text to fit on one line:
-ReturnType ClassName::ReallyLongFunctionName(Type par_name1, Type par_name2,
+ReturnType ClassName::ReallyLongFunctionName(Type par_name1, Type par_name2,
Type par_name3) {
DoSomething();
...
@@ -5183,7 +5229,7 @@ not fit on a single line as you would wrap arguments in a
or if you cannot fit even the first parameter:
-ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
+ReturnType LongClassName::ReallyReallyReallyLongFunctionName(
Type par_name1, // 4 space indent
Type par_name2,
Type par_name3) {
@@ -5231,9 +5277,9 @@ not fit on a single line as you would wrap arguments in a
Unused parameters that are obvious from context may be omitted:
+Unused parameters that are obvious from context may omit the name:
-class Foo {
+class Foo {
public:
Foo(const Foo&) = delete;
Foo& operator=(const Foo&) = delete;
@@ -5243,7 +5289,7 @@ not fit on a single line as you would wrap arguments in a
Unused parameters that might not be obvious should comment out the variable
name in the function definition:
-class Shape {
+class Shape {
public:
virtual void Rotate(double radians) = 0;
};
@@ -5264,7 +5310,7 @@ void Circle::Rotate(double) {}
Attributes, and macros that expand to attributes, appear at the very
beginning of the function declaration or definition, before the
return type:
- ABSL_ATTRIBUTE_NOINLINE void ExpensiveFunction();
+ ABSL_ATTRIBUTE_NOINLINE void ExpensiveFunction();
[[nodiscard]] bool IsOk();
@@ -5275,11 +5321,11 @@ lists like other comma-separated lists.
For by-reference captures, do not leave a space between the
ampersand (&) and the variable name.
-int x = 0;
+int x = 0;
auto x_plus_n = [&x](int n) -> int { return x + n; }
Short lambdas may be written inline as function arguments.
-absl::flat_hash_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.contains(i);
@@ -5322,7 +5368,7 @@ minimum number of lines, including placing multiple arguments
on each line where appropriate.
Function calls have the following format:
-bool result = DoSomething(argument1, argument2, argument3);
+bool result = DoSomething(argument1, argument2, argument3);
If the arguments do not all fit on one line, they
@@ -5330,13 +5376,13 @@ should be broken up onto multiple lines, with each
subsequent line aligned with the first argument. Do not
add spaces after the open paren or before the close
paren:
-bool result = DoSomething(averyveryveryverylongargument1,
+bool result = DoSomething(averyveryveryverylongargument1,
argument2, argument3);
Arguments may optionally all be placed on subsequent
lines with a four space indent:
-if (...) {
+if (...) {
...
...
if (...) {
@@ -5360,13 +5406,13 @@ better addressed with the following techniques.
readability due to the complexity or confusing nature of the
expressions that make up some arguments, try creating
variables that capture those arguments in a descriptive name:
-int my_heuristic = scores[x] * y + bases[x];
+int my_heuristic = scores[x] * y + bases[x];
bool result = DoSomething(my_heuristic, x, y, z);
Or put the confusing argument on its own line with
an explanatory comment:
-bool result = DoSomething(scores[x] * y + bases[x], // Score heuristic.
+bool result = DoSomething(scores[x] * y + bases[x], // Score heuristic.
x, y, z);
@@ -5378,7 +5424,7 @@ which is made more readable rather than a general policy.
Sometimes arguments form a structure that is important
for readability. In those cases, feel free to format the
arguments according to that structure:
-// Transform the widget by a 3x3 matrix.
+// Transform the widget by a 3x3 matrix.
my_widget.Transform(x1, x2, x3,
y1, y2, y3,
z1, z2, z3);
@@ -5394,7 +5440,7 @@ variable name), format as if the {} were the
parentheses of a function call with that name. If there
is no name, assume a zero-length name.
-// Examples of braced init list on a single line.
+// Examples of braced init list on a single line.
return {foo, bar};
functioncall({foo, bar});
std::pair<int, int> p{foo, bar};
@@ -5427,7 +5473,7 @@ MyType m = { // Here, you could also break before {.
At a high level, looping or branching statements consist of the following
components:
if,
+ if,
else, switch, while, do,
or for).if (condition) { // Good - no spaces inside parentheses, space before brace.
+if (condition) { // Good - no spaces inside parentheses, space before brace.
DoOneThing(); // Good - two-space indent.
DoAnotherThing();
} else if (int a = f(); a != 3) { // Good - closing brace on new line, else on same line.
@@ -5539,7 +5585,7 @@ projects require curly braces always.
braces or not, depending on your preference. If you do include curly braces,
they should be placed as shown below.
-switch (var) {
+switch (var) {
case 0: { // 2 space indent
Foo(); // 4 space indent
break;
@@ -5553,7 +5599,7 @@ they should be placed as shown below.
Empty loop bodies should use either an empty pair of braces or
continue with no braces, rather than a single semicolon.
-while (condition) {} // Good - `{}` indicates no logic.
+while (condition) {} // Good - `{}` indicates no logic.
while (condition) {
// Comments are okay, too
}
@@ -5563,7 +5609,7 @@ while (condition) continue; // Good - `continue` indicates no logic.
while (condition); // Bad - looks like part of `do-while` loop.
-Pointer and Reference Expressions
+Pointer and Reference Expressions and Types
No spaces around period or arrow. Pointer operators do not
have trailing spaces.
@@ -5571,7 +5617,7 @@ have trailing spaces.
The following are examples of correctly-formatted
pointer and reference expressions:
-x = *p;
+x = *p;
p = &x;
x = r.y;
x = r->y;
@@ -5587,37 +5633,26 @@ x = r->y;
* or &.
-When referring to a pointer or reference (variable declarations or definitions, arguments,
-return types, template parameters, etc), you may place the space before or after the
-asterisk/ampersand. In the trailing-space style, the space is elided in some cases (template
-parameters, etc).
+When referring to a pointer or reference (variable declarations or definitions, arguments, return
+types, template parameters, etc.), you must not place a space before the asterisk/ampersand. Use a
+space to separate the type from the declared name (if present).
-// These are fine, space preceding.
-char *c;
-const std::string &str;
-int *GetPointer();
-std::vector<char *>
-
-// These are fine, space following (or elided).
+// These are fine.
char* c;
const std::string& str;
int* GetPointer();
std::vector<char*> // Note no space between '*' and '>'
-You should do this consistently within a single
-file.
-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.
-// Fine if helpful for readability.
+// Fine if helpful for readability.
int x, y;
int x, *y; // Disallowed - no & or * in multiple declaration
-int* x, *y; // Disallowed - no & or * in multiple declaration; inconsistent spacing
+int *x, *y; // Disallowed - no & or * in multiple declaration
+int *x; // Disallowed - & or * must be left of the space
char * c; // Bad - spaces on both sides of *
const std::string & str; // Bad - spaces on both sides of &
@@ -5631,7 +5666,7 @@ consistent in how you break up the lines.
In this example, the logical AND operator is always at
the end of the lines:
-if (this_one_thing > this_other_thing &&
+if (this_one_thing > this_other_thing &&
a_third_thing == a_fourth_thing &&
yet_another && last_one) {
...
@@ -5659,7 +5694,7 @@ expression with parentheses.
Use parentheses in return expr; only
where you would use them in x = expr;.
-return result; // No parentheses in the simple case.
+return result; // No parentheses in the simple case.
// Parentheses OK to make a complex expression more readable.
return (some_long_condition &&
another_condition);
@@ -5677,7 +5712,7 @@ return(result); // return is not a function!
(), and {}; the following are
all correct:
-int x = 3;
+int x = 3;
int x(3);
int x{3};
std::string name = "Some Name";
@@ -5694,7 +5729,7 @@ 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 containing 100 items: All 1s.
+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.
@@ -5702,7 +5737,7 @@ std::vector<int> v{100, 1}; // A vector containing 2 items: 100 and 1.
types. This can prevent some types of programming
errors.
-int pi(3.14); // OK -- pi == 3.
+int pi(3.14); // OK -- pi == 3.
int pi{3.14}; // Compile error: narrowing conversion.
@@ -5715,7 +5750,7 @@ always be at the beginning of the line.
of indented code, the directives should start at the
beginning of the line.
-// Good - directives at beginning of line
+// Good - directives at beginning of line
if (lopsided_score) {
#if DISASTER_PENDING // Correct -- Starts at beginning of line
DropEverything();
@@ -5738,7 +5773,7 @@ beginning of the line.
Class Format
-Sections in public, protected and
+
Sections in public, protected, and
private order, each indented one space.
The basic format for a class definition (lacking the
@@ -5746,7 +5781,7 @@ comments, see Class
Comments for a discussion of what comments are
needed) is:
-class MyClass : public OtherClass {
+class MyClass : public OtherClass {
public: // Note the 1 space indent!
MyClass(); // Regular 2 space indent.
explicit MyClass(int var);
@@ -5800,7 +5835,7 @@ with subsequent lines indented four spaces.
The acceptable formats for initializer lists are:
-// When everything fits on one line:
+// When everything fits on one line:
MyClass::MyClass(int var) : some_var_(var) {
DoSomething();
}
@@ -5833,7 +5868,7 @@ MyClass::MyClass(int var)
Namespaces do not add an
extra level of indentation. For example, use:
-namespace {
+namespace {
void foo() { // Correct. No extra indentation within namespace.
...
@@ -5861,7 +5896,7 @@ trailing whitespace at the end of a line.
General
-int i = 0; // Two spaces before end-of-line comments.
+int i = 0; // Two spaces before end-of-line comments.
void f(bool b) { // Open braces should always have a space before them.
...
@@ -5882,17 +5917,17 @@ class Foo : public Bar {
Adding trailing whitespace can cause extra work for
-others editing the same file, when they merge, as can
-removing existing trailing whitespace. So: Don't
+others editing the same file when they merge, as can
+removing existing trailing whitespace. So, don't
introduce trailing whitespace. Remove it if you're
already changing that line, or do it in a separate
clean-up
-operation (preferably when no-one
+operation (preferably when no one
else is working on the file).
Loops and Conditionals
-if (b) { // Space after the keyword in conditions and loops.
+if (b) { // Space after the keyword in conditions and loops.
} else { // Spaces around else.
}
while (test) {} // There is usually no space inside parentheses.
@@ -5920,7 +5955,7 @@ switch (i) {
Operators
-// Assignment operators always have spaces around them.
+// Assignment operators always have spaces around them.
x = 0;
// Other binary operators usually have spaces around them, but it's
@@ -5939,7 +5974,7 @@ if (x && !y)
Templates and Casts
-// No spaces inside the angle brackets (< and >), before
+// No spaces inside the angle brackets (< and >), before
// <, or between >( in a cast
std::vector<std::string> x;
y = static_cast<char*>(x);
@@ -5950,43 +5985,16 @@ std::vector<char *> x;
Vertical Whitespace
-Minimize use of vertical whitespace.
+Use vertical whitespace sparingly; unnecessary blank lines make it harder to
+see overall code structure. Use blank lines only where they aid the reader in
+understanding the structure.
-This is more a principle than a rule: don't use blank lines when
-you don't have to. In particular, don't put more than one or two blank
-lines between functions, resist starting functions with a blank line,
-don't end functions with a blank line, and be sparing with your use of
-blank lines. A blank line within a block of code serves like a
-paragraph break in prose: visually separating two thoughts.
-
-The basic principle is: The more code that fits on one screen, the
-easier it is to follow and understand the control flow of the
-program. Use whitespace purposefully to provide separation in that
-flow.
-
-Some rules of thumb to help when blank lines may be
-useful:
-
-
Do not add blank lines where indentation already provides clear delineation, +such as at the start or end of a code block. Do use blank lines to separate code +into closely related chunks, analogous to paragraph breaks in prose. Within a +statement or declaration, usually only insert line breaks to stay within +the line length limit, or to attach a comment to only +part of the contents.