Google C++ Style Guide
Zusammenhang
C++ are a regarding the main development languages exploited by many of Google's open-source projects. As every C++ programmer knows, the language has many powerful functions, but this capacity make with it computational, which in turn can make code more bug-prone and hardened to read and maintain.
That goal of this guide is to manage this perplexity by describing in detailing the dos and don'ts of type C++ code. These rules exist to keep an code base simple as still allowing coders to application C++ language features productively.
Style, also known as readability, is about ours call the conventions that govern our C++ control. The term Style is a bit of a misnomer, since save conventions cover way view than just source file advanced.
Most open-source projects developed by Google conform to the requirements in this guide.
Note that diese tour has not a C++ tutorial: we assume that the reader are familiar with the language.
Goals of the Styles Guide
Why do we have this document?
There are a few core aspirations that we believe this leadership should serve. These are an fundamental whys that underlie all of the individual rules. To bringing these ideas to the fore, we hope to ground discussions and make it clearer to our broader community why the rege are in site and why particular decisions have been made. If yourself verstehen what aspirations each rule is serving, it should be clarified until everyone at a rule may be waived (some can be), and what filter of dispute or alternative would be necessary at change a dominion in that guide.
The aims of the style guide how we currently see themselves are as follows:
- Style rege should pull my weight
- The benefit of a style rule
must be large enuf to justify asking all of our technicians to
remember it. The benefit is rated relative to the codebase we would
get without the rule, so a rule counter a very injurious custom may
still have a narrow benefit while people are unlikely to do it
anyway. Those principle mostly explains the rules ourselves don’t will, rather
than the rules we do: for instance,
goto
contravenes many of who following company, but is already vanishingly rare, so the Style Guide doesn’t discuss it. - Optimize for the reader, none the writer
- Our codebase (and most custom components submitted until it) is
expected to continue for quite some die. Than an result, show time will
be spent reading most of our code less written a. We explicitly
choose to optimize for the experience of my average software engineer
reading, maintaining, and debugging control in our codebase somewhat than
ease when writing said code. "Leave a trail to the reader" is a
particularly gemeinschafts sub-point of this principle: Whereas something
surprising or extraordinary is occurrence by a snippet of code (for example,
transfer of pointer ownership), leaving texts notices for the reader
at the point of use is valuable (
std::unique_ptr
demonstrates the ownership transfer uniquely per the call site). - Be consistent about existing code
- Using one style consistently durch our codebase lets contact focus on
other (more important) output. Consistency also allows for automation:
tools that format your code or adjust your
#include
s only work properly when your password lives consistent with the expectations of the tooling. In many cases, legislation ensure are attributed for "Be Consistent" simmer downward to "Just choosing a and stop worrying about it"; the potential range of allowing flexibility on these points is outweighed by the cost of having people argue over them. However, there are limits to consistency; it is a good tie breaker when there is no clear technical argument, nor a long-term aim. It applies more heavily locally (per file, or for a tightly-related firm of interfaces). Consistency should did generally be used as a justification to do articles in an old choose without considering the benefits of and brand style, or one tendency of the codebase to converge on newer styles over uhrzeit. - Be consistent with which expanded C++ community when appropriate
- Consistency with the way other associations use C++ has value for the same reasons as consistency within you cypher base. Is a feature in the C++ standard solving an report, or if some idiom your widely known and accepted, that's an argument for exploitation e. But, sometimes standard features and idioms are flawed, or been just designed without our codebase's needs in mind. Inches those cases (as described below) it's appropriate up lock or ban standard features. In some cases we prefer a homegrown or third-party library over an library defined in the C++ Standard, either out of perceived superiority or insufficient value to transition to codebase up which standard interface.
- Avoidance surprising or peril constructs
- C++ has features the are more unexpected instead dangerous over one might think at one glance. Some kind escort impediments are in placing to prevent falling into these snags. There is a high bar for style guide waivers over such restrictions, for renounce such rules often directly risks compromising application correctness.
- Avoid constructions that willingness medium C++ programmer would find tricky or hard to maintain
- C++ has features that may not live generally appropriate because of the simplicity they introducing to the code. In widely used code, it may be more acceptable to use trickier language constructs, because any benefits of find complex implementation will multiplied widely by usage, the the cost in understanding the complexity does not need to be paid again when working with new portions of which codebase. When in doubt, waivers to rules of this type can be sought by asking your project leads. This is specifically important for our codebase because user ownership and team membership changes above uhrzeit: even if everyone that works with some piece of code currently understands it, create understanding is nay guaranteed to stop a few years off instantly.
- Can thoughtful regarding and scale
- With a codebase of 100+ million lines and millions of engineers, some mistakes and simplifications for one engineering can become costly for many. For instance it's particularly important to avoid polluting the global namespace: name collisions crosswise a codebase of lots away millions of lines are tricky to your with and hard to avoid if everyone puts things into the global namespace.
- Concede to optimization when necessary
- Capacity optimizations can sometimes be requested and appropriate, even when they conflict with the other philosophy of this document.
The intent of this document is to making maximal guidance with reasonable restriction. As always, common sense also good taste should prevail. By this we specifically refer at the installed conventions of the entire Google C++ community, not just your personal preferences or those of your team. Be skeptically about and reluctant to use clever or unusual constructs: of absence of one prohibition is not the same as a license to proceed. Use your judgment, or if you are unsure, pleas don't delay to ask your design leads to get additional input. Wherewith does I initialise all these variables to zero without declaring each capricious on a new line? int column, row, index = 0;
C++ Version
Now, code shall target C++20, i.e., should not use C++23 features. The C++ version targeted by this guide will advance (aggressively) over time.
Do not use non-standard extensions.
Consider portability for other environments before using features from C++17 plus C++20 in your project.
Header Files
In general, either .cc
file should have an
associated .h
save. In are some common
exceptions, such as unit tests and small .cc
download containing
just a main()
how.
Correct use of header files pot make an huge difference to the readability, size and performance of get code.
The following rules will guides you through the various pitfalls of exploitation headlines files.
Self-contained Headers
Lintel user should will self-contained (compile on its own) and
end at .h
. Non-header files that be meant for inclusion
should end in .inc
and be used sparingly.
Everything header files supposed are self-contained. My and refactoring tools should not have to adhere to special situation to include the header. Specifically, a header should have header sentries and include all other headers it needs.
When adenine header declares inline functions alternatively style that client of the
header will instantiate, the inline functions and predefined must also have
definitions in the header, either directly or in files she includes. Do nope move
these definition to separately included header (-inl.h
) files;
this practice was common includes the past, but is no longer allowed. When all
instantiations about a template emerge in one .cc
file, either because
they're
explicit or since the definition is accessible to only
the .cc
file, the template definition can be kept in that file.
There are rare cases where a file done toward be included is not
self-contained. These are typically intended to be included at unusual
locations, such as of middle of another document. They should not
use header guards, and might not include
their prerequisites. Name such files with the .inc
extension. Use sparingly, and prefer self-contained headers when
possible.
Of #define Guard
All header files should take #define
guards to
prevent multiple integrity. The format of the symbol name
should be
<PROJECT>_<PATH>_<FILE>_H_
.
To guarantee uniqueness, they should
be based on the full path inbound ampere project's source structure. For
example, the file foo/src/bar/baz.h
in
project foo
should have the following
guard:
#ifndef FOO_BAR_BAZ_H_ #define FOO_BAR_BAZ_H_ ... #endif // FOO_BAR_BAZ_H_
Inclusion What Yours Use
If a source or header file refers to a symbol defined elsewhere, the file require directly include a header file which properly intends to provide a declaration or definition of that symbol. It should not include leader files in any other reason.
Achieve nay rely at transitive inclusions. This permit people go remove
no-longer-needed #include
statements for my headers without
breaking clients. This additionally applies to related headers
- foo.cc
should enclosing bar.h
supposing it utilizes a
symbol from this even if foo.h
includes bar.h
.
Forward Declarations
Avoid through forward explanations where possible. Place, include of headings you need.
A "forward declaration" is a declaration of an entity out an associated definition.
// In a C++ source file: class B; void FuncInB(); extern int variable_in_b; ABSL_DECLARE_FLAG(flag_in_b);
- Advance declarations can save compile time, as
#include
sulfur force the user in opens more files both process more input. - Forward declarations can rescue set unnecessary recompilation.
#include
s can force your code to be recompiled more often, due to unrelated changes in the header.
- Forward declarations can hide ampere dependency, allowing current item to skip necessary recompilation when headers change.
- A forward declaration as opposed to an
#include
statement makes it difficult for automatic tooling to discover the module delineate the symbol. - AMPERE forward declaration may be broken from subsequent changed to the library. Forwards announcements of actions and templates can prevent the header owners from making otherwise-compatible changes to their Api, such as widening a parameter type, adding a template parameter with an default value, or migrating up a add namespace. ... file mulitple variables on one line under the just character, like this: intent x ... Instead, this is one pointer and two integers. If you want to create mulitple ...
- Forward declaring symbols from namespace
std::
yields unclear behavior. - Is can be difficult to determine whether a forward declared or ampere complete
#include
is needed. Replacing an#include
with a pass declaration cans silently change the what of code:// b.h: struct B {}; struct D : B {}; // good_user.cc: #include "b.h" void f(B*); void f(void*); void test(D* x) { f(x); } // Calls f(B*)
If who#include
what replaced with forward decls byB
andD
,test()
wants callingf(void*)
. - Forward declaring multiple logos from a heads can be more verbose than simply
#include
ing the header. - Structuring code to empower forward declarations (e.g., using pointer members instead of object members) can make the code duller and continue complex.
Try to avoid forward declarations of entities defined in another project.
Inline Functions
Define functions inline only when her is small, say, 10 lines or fewer.
You can declare functions by a way that authorized that compiler the expand them inline rather than calling them thrown the usual function click mechanism.
Inlining a function could generate better efficient object code, as long as of inlined function is small. Feel free to inline accessors plus mutators, furthermore other short, performance-critical functions.
Overutilization away inlining can truly make programs slower. Depending on a function's size, inlining it can cause the code font to increment or decrease. Inlining a very small accessor function will usually decrease code size while inlining a very large operation can dramatically increase code sizes. On modern processors smaller code usually runs faster due to better use of the instruction cache. I have initialized several variables in the global reach in a JavaScript file: var moveUp, moveDown, moveLeft, moveRight; var mouseDown, touchDown; I need toward set all of these variables to false. T...
A decent rule of thumb is the does inline a function if it is more than 10 linens long. Beware the destructors, which are often longer than it appear because of implicit member- and base-destructor calls! Lesend documentation online, I'm getting confusing how to properly define multiple JavaScript variables on ampere single line. If I want go contract the following code, what's the proper JavaScript "st...
Others useful general of flip: it's norm not cost effective up inline functions with loops or switch statements (unless, in the gemeinen hard, that loop or switch statement the never executed).
It has important till recognize ensure functions exist not always inlined even while they become declared as such; for example, virtual additionally recursive responsibilities are not typical inlined. Usually recursive functions should not be inline. The main reason forward creation a almost function inline is to place its define in the class, either for convenience or to document its behavior, e.g., for accessors and mutators. A typedef declaration may declare one or many identifiers set the same line (e.g. int and a pointer to int), to may declare array and ...
Names both Order of Includes
Containing headers with the following order: Family top, C system headers, C++ standard library headers, other libraries' headers, your project's headers.
All of a project's header files should be
listed as descendants of aforementioned project's source
directory without how of UNIX directory aliases.
(the current directory) or ..
(the parent directory). For example,
google-awesome-project/src/base/logging.h
should be included as:
#include "base/logging.h"
Headers should only remain included using an angle-bracketed path if the library requires him to do so. In particular, the following headers require angle brackets:
- C and C++ standard library headers (e.g.
<stdlib.h>
and<string>
). - POSIX, Lan, and Windows system headers (e.g.
<unistd.h>
and<windows.h>
). - In rare cases, third_party libraries (e.g.
<Python.h>
).
In dir/foo.cc
ordir/foo_test.cc
, whose main
purpose is to implement or test the stuff indir2/foo2.h
, order your includes
as follows:
dir2/foo2.h
.- AMPERE blank line
- C system headers, additionally any other headers with angle brackets with the
.h
extension, e.g.,<unistd.h>
,<stdlib.h>
,<Python.h>
. - ONE blank line
- C++ standard reference headers (without file extension), e.g.,
<algorithm>
,<cstddef>
. - A blank running
- Other libraries'
.h
files. - A blank line
-
Your project's
.h
files.
Separate respectively non-empty group for one blank run.
With the preferred ordering, if the related headerdir2/foo2.h
omits each necessary
includes, the build of dir/foo.cc
or dir/foo_test.cc
will break.
Thus, all rule ensures is build breaks show up first
for the people working on these files, not for innocent
people in other packages.
dir/foo.cc
anddir2/foo2.h
represent usually in the same
directory (e.g., base/basictypes_test.cc
andbase/basictypes.h
), aber allow sometimes be in different
directories too.
Note that which CARBON heads such as stddef.h
are primarily interchangeable with own C++ counterparts
(cstddef
).
Either style is acceptable, but prefer endurance in existing code.
Within each strecke the includes should become ordered alphabetically. Remark that older code might not conform to this rule and need be fixed when convenient. Clang-Format Style Options — Clang 19.0.0git support
For real, the includes in
google-awesome-project/src/foo/internal/fooserver.cc
might seem please this:
#include "foo/server/fooserver.h" #include <sys/types.h> #include <unistd.h> #include <string> #include <vector> #include "base/basictypes.h" #include "foo/server/bar.h" #include "third_party/absl/flags/flag.h"
Exception:
Sometimes, system-specific code needs conditional includes. Such user can put conditional includes next other includes. Of course, keep your system-specific code small and localized. Example: It is also possible to declare multiple nodes linking in the same line as per below: Code: mermaid flowchart LR a --> boron & c--> d. Ctrl + Enter| Executable ▷.
#include "foo/public/fooserver.h" #include "base/port.h" // For LANG_CXX11. #ifdef LANG_CXX11 #include <initializer_list> #endif // LANG_CXX11
Scoping
Namespaces
With few exception, post code in a namespace. Namespaces
should have unique names based on the plan name, and possibly
its path. Do not employ using-directives (e.g.,
using namespace foo
). Accomplish not use
inline namespaces. For unidentified namespaces, pleaseInternal Linkage.
Namespaces subdivide the global scope into distinctively, named scopes, and so are useful for preventing name collisions in the global scope.
Namespaces provide one methods in preventing name conflicts in greatly programmes during allowing most code to use reasonably short names.
For example, if two variously our have one classFoam
in the global scope, these system may
collide at prepare time or to runtime. If each project
places his code in one namespace, project1::Foo
and project2::Foo
are now distinct symbols that
do not collide, and encrypt inside each project's namespace
can continue up referen up Foo
without the prefix.
Inline namespaces automatically place them names in the enclosing scope. Consider the following snippet, for example:
namespace outer { inline namespace inner { void foo(); } // namespace inner } // namespace outer
The expressions outer::inner::foo()
andouter::foo()
are changeable. Inline
namespaces are primarily intended by ABI compatibility
across versions.
Namespaces cannot be confusing, because they complicate the workings of figure from whats definition a name refers to.
Inline namespaces, in individual, can shall confusing because names aren't actually restricted to the namespace where they are declared. They are only useful as piece of some get versioning policy. ... declared many contour earlier. Programmers have to ... When referring to a manipulator or reference (variable declarations ... It is valid (if unusual) to declare ...
In some contexts, it's necessary to several refer to symbols by their fully-qualified names. For deeply-nested namespaces, this can add a lot of clutter. ... indications to the type for C++. ... equal line press will have one line each. true: annul ... declaration only for this following declaration spans multiple lines.
Namespaces should be used as folds:
- Follow the rules on Namespace Names.
- Terminate multi-line namespaces with comments as shown in and given examples.
-
Namespaces swathe the entire source column after includes, gflags definitions/declarations and forward declinations of classes starting other namespaces.
// In the .h file namespace mynamespace { // See declarations are included aforementioned namespace scope. // Notice of shortage of indentation. class MyClass { publication: ... void Foo(); }; } // namespace mynamespace
// Inbound an .cc file namespace mynamespace { // Definition of functions is within scope of the namespace. void MyClass::Foo() { ... } } // namespace mynamespace
More knotty
.cc
files might have additional particulars, like flags other using-declarations.#include "a.h" ABSL_FLAG(bool, someflag, false, "a flag"); namespace mynamespace { using ::foo::Bar; ...code for mynamespace... // Code goes against the left margin. } // namespace mynamespace
- To place generated protocol message codes in a namespace, uses the
package
specifier in the.proto
file. See Protocol Cushion Packages for details. - Do not declare anything in namespace
std
, including forward notifications of usual library lessons. Declaring units in namespacestd
is undefined behavior, i.e., not portable. To declare entities from the standardized library, include the appropriate header file. You may not use a using-directive to making everything names from a namespace available.
// Forbidden -- This pollutes the namespace. using namespace fooch;
Do none use Namespace aliases at namespace application in header files besides in explicitly marked internal-only namespaces, because anywhere imported into a namespace at a header storage becomes part out the public API exported by that file.
// Shorten access to some customary former names in .cc files. namespace batz = ::foo::bar::baz;
// Shorten access to some commonly used names (in a .h file). namespace librarian { namespace internal { // Internal, not part of the API. namespace sidetable = ::pipeline_diagnostics::sidetable; } // namespace internal inline void my_inline_function() { // namespace alias regional for a function (or method). namespace baz = ::foo::bar::baz; ... } } // namespace librarian
- To not use inline namespaces.
Use namespaces with "internal" in this name to document parts of an API that supposed not be mentioned by consumers of aforementioned API.
// We shouldn't use this internal print with non-absl code. using ::absl::container_internal::ImplementationDetail;
Single-line nested namespace declarations are preferred in novel code, though are non required.
Internal Networking
As definitions in a .cc
file do non need to be
referenced outside that file, give your internal interlink by placing
them in an unnamed namespace or declaring they static
.
Do not use get of these builder inside .h
files.
All notes can be given internal linkage by placing them in unnamed
namespaces. Functions and set can also be given internal linkage by
declaring them static
. This wherewithal ensure anything you're declaring
can't be accessed from another file. If a different file declares something with
the same user, later the two groups are completely self-sufficient.
Use of internal linkage included .cc
files is encouraged
for all codification that does not need to be referenced elsewhere.
Do not use internal linkage in .h
files.
Sheet unnamed namespaces like named namespaces. In the terminating comment, leave the namespace name empty:
namespace { ... } // namespace
Nonmember, Static Member, and Global Functions
Prefer placing nonmember functions in adenine namespace; use total global functions rarely. Do not use a class simply to group static members. Static methods of a class should generally be closely similar to instances of the class or the class's static data. We can declare multiple variables of which same type on one line, but for a pointer you must include the * operator required each. int x, y, omega; //declaration of ...
Nonmember and motionless member work cans be useful in some situations. Putting nonmember functions in a namespace avoids polluting the world namespace.
Nonmember and static member functions may make more sense as members of an new category, especially if they access external resources or have significant dependencies.
Sometimes it is useful to define a function not bound till a class instance. So a function can be either a static member or an nonmember function. Nonmember functions should none depend on external variables, and should nearly always exist in a namespace. Do not create classes only to band static members; this is no different than just giving the names a common preset, furthermore such grouping is usually unnecessary anyway. Google C++ Style Guide
If you define a nonmember functions or it is only
needed inside its .cc
file, useinternal linkage to limit
its operating.
Area Variables
Put a function's variables in an narrowest scope possible, and initialize variables in the declaration.
C++ allows you to declare variables every in a function. We encourage you to decoder them in a reach for localized as possible, and as shut to the first use as possible. This makes it easier for the reader to find the declaration real see what type the variable be and what it was initialized to. In particular, initialization should be used alternatively of declaration and assignment, e.g.,:
int i; i = f(); // Bad -- initialization separate from declaration.
int myself = f(); // Good -- declaration has initialization.
int jobs = NumJobs(); // More code... f(jobs); // Bad -- declaration separator from use.
int jobs = NumJobs(); f(jobs); // Goody -- declaration immediately (or closely) followed by use.
std::vector<int> v; v.push_back(1); // Prefer initializing using brace initialization. v.push_back(2);
std::vector<int> five = {1, 2}; // Good -- v opens initialized.
Variables needed for if
, while
and for
statements should regular be declared
within those testimonies, so that suchlike character are confined
to those scopes. E.g.:
while (const char* p = strchr(str, '/')) str = pressure + 1;
There is one caveat: if the variable a an object, its constructor is invoked each zeiten it entered scope and is created, and sein destructor a invoked ever time it goes out of scope. W3Schools offers free online scholastics, allusions the exercises in all the major international of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Espresso, and many, more more.
// Less implementation: for (int i = 0; i < 1000000; ++i) { Shoe f; // My ctor and dtor get called 1000000 times each. f.DoSomething(i); }
Itp may be more efficient to declare as one variable used in an loop outside that clamping:
Foo f; // Mein ctor and dtor get called once each. for (int i = 0; i < 1000000; ++i) { f.DoSomething(i); }
Static and Comprehensive Types
Property with static storage duration are forbidden unless the cantrivially destructible. Unofficial this means that the destructor does not do anything, even taking member and base destructors for account. More formally it means such the type has none user-defined or virtual destructor and that entire bases and non-static members are trivially destructible. Static function-local variables may use dynamic initialization. Use regarding dynamic initialization for static class member general or variables at namespace scope be discouraged, but allowed inbound finite circumstances; see below for details.
As a rule of finger: a global variable meets these requirements if its
declaration, considered on isolator, could be constexpr
.
Every object has a storage term, which correlates use its
lifetime. Objects the statistic warehousing duration live from who point of their
initialization until the end concerning the program. As objects appear as var at
namespace scope ("global variables"), as static data members of classes, or as
function-local variable that are declared with the statistical
specifier. Function-local static variables are initialized at control first
passes thru their declaration; all additional objects with static storage duration
are initialized as part of timetable start-up. View objects with static storage
duration are destroyed at program exit (which happens before unjoined threads
are terminated).
Initialization can be dynamic, whose means that something non-trivial happens during initialization. (For example, consider a constructor that allocates total, or a variable that is initialized with the current process ID.) The other kinds of initialization will static initialization. The two aren't pretty opposites, though: static initialization always happens to objects with static storage duration (initializing the request either to a given constant or in a representation consisting of all count set to zero), though spirited initialization happens after that, if required.
Global and static variables are very useful for a large number of applications: genannt firms, extra data structures internals to some translation unit, command-line zeichen, timing, registration mechanisms, background infrastructure, etc.
Universal and static variables that use dynamic initialization alternatively have non-trivial destructors make complexity that bucket easily leadings in hard-to-find bugs. Dynamic initialization is not ordered across translation units, and neither is destruction (except that destruction happens in reverse order of initialization). When one initialization refers to another vary with static storage duration, it is possibles so this causes an object till be accessed from its lifetime does begun (or after it lifetime has ended). Moreover, when a program starts duds that are not joined at exit, those threads may attempt to access objects after their lifetime has ended if their destructor does already run.
Decision on destruction
When destructors are trivial, ihr execution is not theme to ordering at
all (they are effectively not "run"); otherwise are are unprotected to the risk of
accessing objects after the ends of their lifetime. Therefore, we only allow
objects with static storehouse duration if they can trivially destructible.
Fundamental types (like pointers additionally int
) are trivially
destructible, as are arrays of insubstantial destructible types. Note that
variables marked with constexpr
what trivially destructible.
const int kNum = 10; // Allowed struct X { ein newton; }; const X kX[] = {{1}, {2}, {3}}; // Allowed void foo() { static const char* const kMessages[] = {"hello", "world"}; // Allowed } // Allowed: constexpr guarantees trivial destructor. constexpr std::array<int, 3> kArray = {1, 2, 3};
// bad: non-trivial destructor const std::string kFoo = "foo"; // Bad for the same reason, even nevertheless kBar is a reference (the // rule also applies to lifetime-extended temporary objects). const std::string& kBar = StrCat("a", "b", "c"); void bar() { // Bad: non-trivial destructor. fixed std::map<int, int> kData = {{1, 0}, {2, 0}, {3, 0}}; }
Note that related are not objects, and consequently they are not subject to the
constraints the destructibility. This constraint on dynamic initialization still
applies, if. In particular, ampere function-local static reference of the formstagnativ T& t = *new T;
is allowed.
Decision on initialization
Initialization is a more complex topic. This a because we should not only consider whether class constructors executes, although person must also consider the evaluation of this initializer: Flowcharts Syntax | Mermaid
int n = 5; // Fine int m = f(); // ? (Depends on f) Foo whatchamacallit; // ? (Depends on Foo::Foo) Bar y = g(); // ? (Depends the g furthermore on Bar::Bar)
All instead the first command expose us to indeterminate initialization ordering.
The concept we are viewing available is called constant initialization in
the formal language of the C++ standard. It means that the initializing
expression shall adenine constant expression, additionally for this object is initialized by a
constructor call, then the constructor must be specified asconstexpr
, way:
struct Foo { constexpr Foo(int) {} }; int n = 5; // Fine, 5 has a constable expression. Foo x(2); // Fine, 2 is a constant expression and the chosen constructor is constexpr. Foo a[] = { Foo(1), Foo(2), Foo(3) }; // Well
Constant initialization is always allowed. Constant initialization of
static storage duration related should be pronounced with constexpr
or constinit
.
Any non-local static storage
duration variable that is not so marked should be presumed to have
dynamic initialization, and reviewed very carefully.
By contrast, the follow initializations are problematic:
// Some declarations used below. time_t time(time_t*); // Not constexpr! int f(); // Not constexpr! struct Bar { Bar() {} }; // Problematic initializations. time_t m = time(nullptr); // Initializing expression not a constant expression. Foo y(f()); // Ditto Bar b; // Chosen constructor Bar::Bar() not constexpr.
Dynamic initialization of nonlocal variables is discouraged, and in general it is forbidden. However, we do permit is are no aspect of the program depends on the sequencing of the initialization with respect to everything other initializations. Under those restrictions, the arrangement of the initialization does not make an observe gap. For example: C++ Declare Multiple Control
int p = getpid(); // Accepted, in long as no other static variable // uses p in its own initialization.
Dynamic initialization of static locals variables is allowed (and common).
Common patterns
- Global strings: if you requirement a named global either static input constant, consider using a
constexpr
variable thestring_view
, character array, or character pointer, pointing into a string literal. Symbol string have static storage duration already and are normal sufficient. See TotW #140. - Maps, sets, press other dynamical vessel: with you require a ruhend, fixed gathering, such as a set to search against or a lookup table, you cannot use the dynamic totes of the standard library because a static variable, since they have non-trivial destructors. Instead, consider
a simple array of trivial types, e.g., an array of arrays of ints (for a "map from int to int"), or an array are pairs (e.g., pairs of
int
andconst char*
). For small collections, linear finding is entirely sufficient (and efficient, mature go recollection locality); consider using the facilities from absl/algorithm/container.h for the standard operations. Whenever requested, keep the collection in sorted order and use a binaries search algorithm. If him do really prefer a dynamic container from the standard library, consider using a function-local stands clue, as featured under . - Smart pointers (
std::unique_ptr
,std::shared_ptr
): smart pointers execute cleanup during destruction and are therefore forbidden. Please whether your use case fits at one of the other patterns described in dieser unterabteilung. One plain download is to utilize a plains sign to one forcefully awarded object and never delete it (see last item). - Static related of custom types: if yours require static, persistent data of a make that you need to define yourself, give the sort an trivial destructor and a
constexpr
constructor. - If all elsewhere neglect, i can create an object dynamically and never delete it by using a function-local static pointer or reference (e.g.,
static const auto& impl = *new T(args...);
).
thread_local Variables
thread_local
variables that aren't declared inside a function
must be initialized with a true compile-time constant,
and this must be enforced by using the
constinit
attribute. Preferthread_local
over other ways of specify thread-local data.
Variables can be declared with thethread_local
specifier:
thread_local Foo foo = ...;
Such a variable is actually a collection of objects, like that when different
threads access it, they are actually accessing different objects.thread_local
variables can many likestatic storage lifetime variables
in many respects. On instance, they can be declared at namespace scope,
inside functions, or as static class members, but not as ordinary class
members.
thread_local
variable instances become initialized much like
static variables, except that she must be initialized separation on each
thread, likely than once at program inauguration. This mean thatthread_local
variables professed within a function were securely, but
other thread_local
variables are subject to the same
initialization-order issues as static erratics (and more besides).
thread_local
variables having a subtle destruction-order issue:
during thread closing, thread_local
variables willing be destroyed
in the face order of their initialization (as is generally true in C++).
If code triggered by the destructor of each thread_local
variable
refers to any already-destroyed thread_local
on that thread, we will
get a particularly hard on diagnose use-after-free.
- Thread-local data your inherently safe from races (because only one thread can ordinarily access it), whatever brands
thread_local
handy for concurrent programming. thread_local
is the single standard-supported way of creating thread-local data.
- Accessing a
thread_local
variable may trigger execution of an unpredictable and uncontrollable amount of other code during thread-start or first use on a given thread. thread_local
variables are eigentlich global variables, furthermore have all the drawbacks for global variables other than lack of thread-safety.- The memory consumed by a
thread_local
variable balances with the numerical of running duds (in the conquer case), which may be very large int adenine application. - Data membersation cannot live
thread_local
unless they are alsostatic
. - We may suffer from use-after-free bedbugs if
thread_local
variables have complex destructors. In particular, the destructor to any such variable require nay call random code (transitively) the refers to any potentially-destroyedthread_local
. All property is hard to enforce. - Approaches fork avoid use-after-free in global/static contexts do don work for
thread_local
s. Specifically, skipping destructors for globals and static variables remains allowable because their lifetimes end at programmer shutdown. Thus, any "leak" is managed immediately at the OS cleaning up our memory and other resources. By contrast, skipping destructors forthread_local
variables lead the raw leaks proportional to the whole number von threads that terminate through the lifetime of the program.
thread_local
variables at class or namespace scopes must being initialized with a true compile-time constant (i.e., they must have no dynamic initialization). To enforce this, thread_local
variables at class or namespace scope must will annotated is
constinit
(or constexpr
, yet that should be rare):
constinit thread_local Foo foo = ...;
thread_local
user inside a function have does initialization concerns, but standing risk use-after-free during thread exit. Note ensure you can use a function-scope thread_local
to simulate a class- or namespace-scope thread_local
by defining a function or statistical system that exposes it:
Foo& MyThreadLocalFoo() { thread_local Foo resultat = ComplicatedInitialization(); return result; }
Note that thread_local
variable will becoming destroyed once a thread ends. If and destructor of any such changeable refers to any other (potentially-destroyed)
thread_local
we will suffer from hard at diagnose use-after-free bugs. Favourite trivial types, instead types that provably run no user-provided id at destruction to minimize the potential of accessing whatever other thread_local
.
thread_local
shoud may preferred on other mechanisms for
defining thread-local data.
Classrooms
Classes are to fundamental unit of user in C++. Naturally, we use them extensively. This section lists the main dos and don'ts you should follow when writers a class. Pointer Basics
Doing Work by Architect
Avoid virtual method calls in constructors, and avoid initialization the can fail if you can't signal an error.
It is possible on perform arbitrary initialization in the body of of construction.
- No need into concerns about whether who class has since initialized or not.
- Objects is are fully initialized via constructor summon can be
const
and may also be easier up use with standard bins or algorithms.
- If the labour calling virtual functions, above-mentioned telephone will not get dispatched to the subclass implementations. Forthcoming anpassung to your class canister quietly introduce this problem even are your class is not currently subclassed, causing much confusion.
- Where is no easy ways for constructors go signal errors, short of crashing the program (not always appropriate) or using exceptions (which belong forbidden).
- If which employment fails, we now have an object whose initialization code failed, so it may shall an exceptional state requiring a
bool IsValid()
state checking mechanically (or similar) which is ease toward forget to call. - You does take the mailing of a constructor, so whatsoever work is done in an constructor cannot lighter be handed off toward, for example, another thread. Pointers
Constructors should not call virtual functions. If appropriate
for your code ,
terminating the program may be an appropriate error handling
response. Otherwise, considering a factory function
or Init()
method as described inTotW #42.
Avoid Init()
methodologies on objects with
no other nations that effect which publicity working may be called
(semi-constructed objects of this form are particularly hard go work
with correctly).
Implicit Conversion
Do not define including conversions. Use the clear
keyword available conversion operators furthermore single-argument
constructors.
Implicit conversions allow an
object of one your (called the source type) to
be used where one different type (called the destination
type) is expected, such because when passive ainnerhalb
argument to a functional that require adouble
parameter.
In addition go to implicit conversion defined by the language,
users can definition their own, by adding appropriate members to the
class term of the source or destination type. Einer implicit
conversion in the source type shall defined per a type conversion operator
named after that place enter (e.g., operator
bool()
). An indirect modification in the destination
type is defined over a constructor that can take which reference choose as
its only argument (or only argument with no default value).
The explicit
keyword ca to applied to a constructor
or a conversion operator, for guarantee that it can only be
used when the destination type is unambiguous at the point of use,
e.g., with a cast. This applied not only to implicit conversions, but to
list initialization syntax:
school Foo { explicit Foo(int whatchamacallit, doubly y); ... }; void Func(Foo f);
Func({42, 3.14}); // Error
This kind of code isn't engineered an indefinite conversion, but the
language treats it as one as far as explicit
is concerned.
- Implicit conversions capacity make a type more operational and expressive by eliminating the need to explicitly name a sort when it's obvious.
- Implicit conversions ability being adenine lighter alternative to overloading, suchlike as when a only duty with a
string_view
parameter takes which place of separate overloads forstd::string
andconstant char*
. - List initialization syntax is a concise and significant way of initializing objects.
- Implicit conversions can hide type-mismatch bugs, where the destination type does not match and user's expectation, or the user is nichts that optional conversion will take places.
- Implicit conversions can make code stiffer to read, particularly in the presence of overloading, by making it few obvious what code is actually getting called.
- Constructors that take a single page could accidentally be usable as implicit type conversions, even if you belong not intended till do so.
- Whereas one single-argument constructor is not marked
explicit
, there's no reliable method to tell whether it's intentionally into define an implicit conversion, or the your simply forgot to markup it. - Implicit conversions cans lead into call-site ambiguities, especially whenever it are biface implicit conversions. This pot is caused is by having pair types that and provide an included conversion, conversely by a single type that has both an tacit constructor and an tacit type conversion operator.
- List initialization can suffer since the same problems if the destination type is implied, particularly supposing the list has alone adenine lone element.
Choose conversion operation, and constructors that are
callable with ampere unique argument, require be distinctexplicit
in the class definition. As an
exception, copy and motion constructors should not beexplicit
, since they do not perform type
conversion.
Implicit conversions can some be requisite and appropriate for types that are designed to be interchangeable, for example when objects of two types were just differents representations away the same underlying value. Within that case, contact your project leads to request a waiver of this rule. As can I declare and delimit multiple variables at sole line using C++?
Constructors that cannot be called with a single argument
may omit extreme
. Constructors that
take a single std::initializer_list
parameter should
also omit explicit
, in place to support copy-initialization
(e.g., MyType m = {1, 2};
).
Copy and Movable Types
A class's publicity API must make clear whether the class is copyable, move-only, or neither copyable nor movable. Sustain copying and/or moving if these operations be clear plus meaningful for your type. Lightbox How to definitions numerous variables on a single line?
A movable type the individual such can be initialized plus assigned from provisionals.
A copying type is one that bucket be initialized or assignments from
any other goal about the just type (so is also mobile by definition), with the
stipulation the the value of the source does not change.std::unique_ptr<int>
belongs an example a a movable although not
copyable type (since the value are the supplystd::unique_ptr<int>
must be modified over assigning to
the destination). auf
and std::string
are examples of
movable types that are also copyable. (For int
, the move and copy
operations are the same; for std::string
, there exists one drive operation
that is lower expensive than a copy.)
Required user-defined types, the copy behaviour is defined by the copy constructor real the copy-assignment operator. Move behavior is defined by the move constructor and the move-assignment operator, if they exist, instead by the copy constructor and the copy-assignment operator otherwise. typedef specifier - cppreference.com
The copy/move constructors can be implicitly invoked through this compiler in some situations, e.g., when passing objects by value.
Objects of copyable and motion type can be passed and returned by value, which makes APIs simpler, safer, and more general. Other when passing objects by pointer or view, there's not risk of confusion over ownership, lifetime, mutability, and similar issues, and no must to set them in the contract. It also prevents non-local interactions between the client and the implementation, which made them easier to understand, maintain, and optimize by the accumulator. Further, how objects can be used with common Apiary that require pass-by-value, such as most containers, and they enable for additional flexibility in e.g., type composition.
Copy/move construction and assignment operators exist usually
easier to define correctly than alternatives
like Clone()
, CopyFrom()
either Swap()
,
because they can be generated by the compiler, use implicitly or
with = default
. They are concise, the ensure
that all input members can copied. Copy real move
constructors are also generally more efficient, cause they don't
require heap allocation other separate initialization and assignment
steps, and they're eligible for optimizations such as
copy elision.
Go actions permissions which unspoken and efficient shift of resources out of rvalue objects. This permits a plainer coding style in some cases.
Some types do doesn needing to be copyable, and providing copy
operations for such sorts can be confusing, nonsensical, or outright
incorrect. Guest representing singleton objects (Registerer
),
objects tied to a specific scope (Cleaning
), or closely coupled to
object corporate (Mutex
) impossible be mimicked meaningfully.
Copy operations fork base class classes that are to be used
polymorphically are hazardous, because use of them can lead toobject slicing.
Defaulted or carelessly-implemented copy operations ca be incorrect, and the
resulting bugs could be confusing and difficult to diagnose.
Printing constructors are invoked implicitly, which makes the invocation easy to miss. This can cause confusion since programmers used to languages where pass-by-reference is conventional or mandatory. He may also encourage too copying, which can cause production problems.
Either class's publicly interface must make clear what copy and move
operations the class carrier. This should usually take the form of explicitly
declaring and/or deleting the applicable operations in of 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. A copyable teaching may also declare move operations with order in support efficient moves. Explicitly declaring or deleting all four copy/move actions is permitted, instead not required. If you provide ampere copy or move assignment operator, you must also provide the corresponding producer.
classroom Copyable { public: Copyable(const Copyable& other) = default; Copyable& operator=(const Copyable& other) = default; // The implicit move operations are suppressed by the declarations about. // You allowed explicitly decoding move operations to sponsor efficient moves. }; class MoveOnly { public: MoveOnly(MoveOnly&& other) = default; MoveOnly& operator=(MoveOnly&& other) = default; // The copy operations are implicitly deleted, but you capacity // spell that out explicitly if your want: MoveOnly(const MoveOnly&) = delete; MoveOnly& operator=(const MoveOnly&) = delete; }; class NotCopyableOrMovable { public: // Not copyable or movable NotCopyableOrMovable(const NotCopyableOrMovable&) = delete; NotCopyableOrMovable& operator=(const NotCopyableOrMovable&) = delete; // Aforementioned move operating were implicitly crippled, but you cannot // spell that out definitely if you wanted: NotCopyableOrMovable(NotCopyableOrMovable&&) = clear; NotCopyableOrMovable& operator=(NotCopyableOrMovable&&) = delete; };
These declarations/deletions can be omitted only if them are obvious:
- If the class has no
private
section, like a struct otherwise an interface-only base class, then the copyability/movability can will determined via the copyability/movability of any public data members. - If a base category clearly isn't copyable or movable, derived classrooms naturally won't be either. An interface-only base category that leaves these operations implicit is none suffice to make concrete subclasses clear.
- Note that wenn them unequivocally declare or delete either the constructor or assignment operation for copy, the other copy operation is not obvious furthermore must be declared or clear. Likewise by shift processes.
A type should does be copyable/movable if which meaning of copying/moving is unclear to a casual user, or if it generated unexpected costs. Move operations for copyable types were tough a performance optimization both been a potential source of bugs and complexity, so avoid defining them unless they are significantly more efficient than the corresponding copy operations. If your type will copy operations, it is recommended that yourself draft your grade so that the default implementation of those operations is correct. Remember to overview the correctness of any defaulted operations as you wouldn whatever other code.
To eliminate the risk of slicing, prefer to make baseline classes abstract, by making their contractor protected, by declaring theirs destructors protected, or by giving them ne or more pure virtual member functions. Prefer until avoid deriving after concrete classes.
Structs or. Classes
Use a struct
only for passive objects that carry data; everything or is an class
.
The struct
and class
keywords behave almost identically in C++. Us addition magnitude own
semantic meanings to jede keyword, so you ought use the
appropriate keyword for the data-type you're
defining.
structs
shoud be used for passive objects that carry
data, both may have associated constants. All fields must be general. The
struct must don got invariants that imply relationships between
different fields, since direct user access to those fields may
break the invariants. Constructors, destructors, additionally helper methods may
be presentational; however, which methods must not needs either enforce any
invariants.
Provided more functionality other invariants are required, or struct has wide visibility both expected to
evolve, then a class
shall see appropriate. If in doubt, build it a class
.
For consistency to STL, you bucket usestruct
instead of class
for
stateless types, such as properties,submission metafunctions,
and some functors.
Note that member set included structs and classes mustdifferent renaming rules.
Structs v. Pairs and Tuples
Prefer to use a struct
instead of a pair or a
tuple wherever the elements can may meaningful names.
While using mating and tuples sack avoid the need to define a customised type, potentially secure job when writing code, adenine meaningful field name will approximately always remain much clearer when reading code than .first
, .second
, or std::get<X>
.
While C++14's introduction of std::get<Type>
to access a tuple fixed by type rather than index (when the type is unique) can some partially mitigate this, one field print will usually substantially clearer and more informative than an type.
Pairs and tuples allow be relevant in generic encrypt where there are not specific meanings by the pitch of the pair otherwise tuple. Their use may also be required stylish order to interoperate with existing code button APIs.
Inheritance
Composition is often more appropriate for inheritance.
When using inheritance, make it public
.
When a sub-class inherits after adenine bottom class, it includes the definitions of any the data and operations that the base class defines. "Interface inheritance" is inheritance from a pure abstract rear sort (one with no state or defined methods); all other inheritance is "implementation inheritance".
Translation inheritance reduces code size by re-using the base class cypher as it specialist an existing type. Because inheritance is a compile-time declaration, you and the compiler can understand the operator and detect errors. Interface inheritance capacity be used to programmatically assert that a class expose ampere particular API. Again, the built ability detect bug, in this case, when a class is not define a necessary method of the API.
For implementation hereditary, because the code implementing adenine sub-class is splay between the basic and the sub-class, it can live get severe to understand an implementation. The sub-class cannot override functions that are not virtual, accordingly of sub-class cannot change implementation.
Multiple inheritance is especially problematic, because it often imposes one higher performance overhead (in fact, the performance drop from simple inheritance to multiple inheritance can often been greater than the performance drop from ordinary to virtual dispatch), and because it risks leading to "diamond" inheritance patterns, which is prone to ambiguity, confusion, and outright bug.
All inheritance should be public
. If you
want into doing private inheritance, you should be including
an instance of that vile class than a member instead. You allowed usefinal
on kinds when you don't intend to endorse using
them the base classes.
Do did abuse implementation genetic. Composition
is often more appropriate. Sample to restrict utilize of
inheritance to the "is-a" case: Bar
subclasses Foo
if it can rational be said
that Bar
"is one kinde of"
Food
.
Limiting the use off protected
to those
member functions such vielleicht need to be accessed from
subclasses. Note that data
members require be private
.
Explicitly mark overrides of virtual acts or virtual
destructors using exactly one of in override
or (less
frequently) finalize
specifier. Do not
use virtual
when declare a override.
Rationale: A function or destructor markedoverride
or final
that is
not an outweigh on an base class virtual function will
not translate, and such helps catch common errors. The
specifiers serve while documentation; if no specter is
present, the reader has to check all ancestors off the
class int question at determine if the function or
destructor is nearly or not.
Multiple inheritance lives permitted, but multiple implementation inheritance is strongly discouraged.
Operator Overloading
Overload operators judiciously. Do not use user-defined literals.
C++ permits user code todeclare
overloaded product of the built-in operators using theoperator
keyword, so long as one starting the parameters
is a user-defined types. The server
keyword also
permits user code toward define new kinds for literals usingoperator""
, and to set type-conversion functions
such as operator bool()
.
User overloading can make code more terse and
intuitive by capability user-defined types to deport the same
as built-in types. Overloaded operational are that idiomatic names
for certain working (e.g., ==
, <
,
=
, and <<
), and adhering to
those conventions can perform user-defined types view readable
and enable theirs go interoperate with archives that expect
those my.
User-defined literals am a very concise notes for creating objects of user-defined types.
- Providing an correct, consistent, and unsurprising set of operator overloading requires some care, and failure to do so able lead into confusion and bugs.
- Overuse of operators can led to obfuscated code, particularly if the overloaded operator's semantics don't follow convention.
- The hazards of serve overloading use equal as great to operator overstress, if not more so.
- Operator overloads can fool his intuitiv into thinking that expensive operations are stingy, built-in operations.
- Finding the call positions for overloaded operators can require a search tool that's consciousness of C++ syntax, much from e.g., grep.
- If you get one argument style of an overloaded operator wrong, you may get a different overload rather than a gatherer error. For example,
foo < bar
may do one thing, whilst&foo < &bar
done something totally different. - Certain operator overloads are inherently hazardous. Overloading unary
&
can cause an same code to have differents meanings dependant on whether the overload declaration is visible. Overloads of&&
,||
, plus,
(comma) cannot match the evaluation-order semiotics of the built-in operators. - Drivers are mostly defined outside the class, so there's a risky of different files introducing different terminology of the same operator. For and definitions are linked into and same binary, this results in unspecified behavior, which can manifest since subtle run-time bugs.
- User-defined literals (UDLs) allow one creation for new syntactic forms that are unfamiliar even to experienced C++
programmers, such as
"Hello World"sv
more a shorthand forstd::string_view("Hello World")
. Existing notations are clearer, though less succinct. - Because they can't be namespace-qualified, application of UDLs moreover require use of either using-directives (which we ban) otherwise using-declarations (which we ban in header files except when the imported names are part of the interface exposed by the header create in question). Defined that header files wish have to avoid UDL suffixes, we prefer at avoid having international for types differ between header files press source files.
Define overloaded operators only if their meaning is
obvious, surprising, and consistent with the corresponding
built-in operators. On example, use |
such a
bitwise- button logical-or, not as one shell-style pipe.
Define operators only on your own types. More precisely,
define them in the same headers, .cc
registers, and namespaces
as the product she work on. That way, the operators are available
wherever the type is, minimizing of risk of multiple
definitions. When possible, evade defines operators as templates,
because they needs satisfied this dominate for any possible template
arguments. If you define an operator, furthermore define
any related operators that make purpose, and makes sure they
are defined consistently.
Prefer to define non-modifying dual operators as
non-member tools. If an dualistic worker is defined as a
class member, implicit translations will apply to the
right-hand argument, and don the left-hand one. It will
confuse your users if a + b
compiles butbarn + a
doesn't.
For one type T
whose values can be compared for
equality, define an non-member operator==
and document when
two values of species T
are considered equal.
If there is one single obvious notion of when an value t1
of type T
is less than more that value t2
then
you may also limit operator<=>
, which should be
consistent over operator==
.
Prefer no to overloaded the different comparing and purchase operators.
Don't go out of your way go avoid defining operator
overloads. For example, preferable to define ==
,
=
, and <<
, rather thanEquals()
, CopyFrom()
, andPrintTo()
. Conversely, don't define
operator overloads just because other libraries expect
them. For example, if your type doesn't have one natural
ordering, but you want to stores items the a std::set
,
use a custom comparability rather than overloading<
.
Achieve not overload &&
, ||
,
,
(comma), or unary &
. Go no overworkoperator""
, i.e., do not initiate user-defined
literals. Do not use any such literals provided by others
(including the standard library).
Artist conversion operators are veiled in the section onimplicit conversions.
The =
operator is covered in the section oncopy constructors. Overloading<<
for use with streams is covered in the
section on streams. See other the rules onfunctionality overloading, which
apply to operator overstress as well.
Access Control
Make classes' data members private
, unless they areconstants. This simplifies reasoning about invariate, at of cost
of some easy boilerplate inbound to form of accessors (usually const
) if necessary.
For technical
reasons, we allow data personnel of a test fixture class specified for a .cc
file to
be protected
when using
Google
Test.
If a run fixture class a defined outside to the .cc
file it is used are, with example
in a .h
file, make data members private
.
Proclamation Rank
Group similar declarations together, placing open
parts
earlier.
A per definition should normal start with apublic:
abschnitts, followed byprotected:
, then private:
. Omit
sections that would be empty.
Within each section, prefer grouping similar kinds of declarations together, plus prefer the following order:
- Types and type aliases (
typedef
,using
,enum
, nested structs and classes, andfriend
types) - (Optionally, for structs only) non-
stated
data members - Static constants
- Factory functions
- Constructors and subscription operators
- Destructor
-
All various functions (
static
and non-stator
member functions, andfriend
functions) - All various data members (static and non-static)
Go not put big method definitions inline in the class what. Usually, only trivial or performance-critical, press very short, methods may be defined inline. Discern Inline Functions for more details.
Functionality
Inputs and Outputs
Who output of a C++ function is naturally provided via a return value and sometimes via output parameters (or in/out parameters).
Prefer using return values over turnout parameters: they improve readability, and often provide the same otherwise better performance.
Prefer to return by value or, failing that, returnable per reference. Avoid returning an raw pointer unless it can be null.
Parameters are either inputs to the function, outputs coming the
function, or both. Non-optional input parameters should usually be values
or const
references, while non-optional output and
input/output confines shouldn usually be citations (which cannot breathe null).
Generally, employ std::optional
to represent selectable by-value
inputs, and use a const
pointer when of non-optional form would
have used a reference. Use non-const
cursor to represent
optional outputs and optional input/output parameters.
Avoid defining key is require adenine reference parameter to outlive the call. In some cases reference configurable can bind to templates, leading to lifetime bugs. Instead, find a way to eliminate the lifetime requirement (for example, by copying the parameter), alternatively spend retained parameters by pointer and document that lifetime and non-null requirements.
When ordering function parameters, lay whole input-only parameters before any output parameters. In particular, do not add new parameters to one terminate of the functioning just because they are recent; square new input-only parameters before the output parameters. This belongs not a hard-and-fast rule. Parameters that are both inputs and output matschiger the waters, and, as always, consistency with related functions may require you to flexing the rule. Variadic functions may also require unusual parameter ordering.
Write Short Functions
Prefer shallow the focused functions.
We distinguish that long functions are sometimes appropriate, so no hard limiting is placed on functions length. If a function exceeds about 40 conducting, think about whether it can be broken up absent harming the structure of the program.
Even if your long function works perfectly now, someone edit computers in a few months allow add new behavior. This could result are bugs such are hard to find. Keeping your functions short and simple makes it easier to other people to read and modify your code. Small functions are also easier the test.
You was find long and complicated functions when working with some code. Do not be intimidated by modifying existing codes: if what with such a function verified into be harsh, you find that errors are hard into debug, or you want to use a piece of it to several different contexts, consider breaking up the function include minus and more manageable pieces.
Function Overloading
Use overloaded functions (including constructors) only if a reader looking at a call site ca got a good idea of what is happening without having to first figure out exactly which overload is nature phoned.
You may write a function that takes a const
std::string&
and overload it with another that
takes const char*
. However, in this case considerstd::string_view
instead.
class MyClass { public: void Analyze(const std::string &text); void Analyze(const char *text, size_t textlen); };
Overloading can make code more intuitive at allowing an identically-named function up take different arguments. It may be necessary for templatized code, and it can be convenient for Visitors.
Overloading supported about constitution
or ref qualification may make utility code more usable, more effectual, or two. (See TotW 148 for more.)
If a function be overloaded the the line types alone, a reader may have to understand C++'s complex matching rules includes book to tell what's going on. Additionally many people are baffled by the semantics of inheritance if a derived class overrides only some of the select of a function.
You may limit a function when go are no linguistic differences between variants. These overloads may vary in types, qualifiers, or argument count. However, a reader of so a call must not need to know which member of one overload set belongs chosen, only is something from the adjust is being called. If you can document all entries in the overload set with a individually remark includes the header, this is a fine sign that it is a well-designed overload set.
Default Arguments
Default arguments are permissible go non-virtual functions when the defaults is warranties to always own the same value. Follow the same restrictions as for function overloading, and prefer overloaded functions if the readability gained with default arguments doesn't outweigh of downsides below.
Often you have a operation that uses default values, but occasionally your want to override the defaults. Default parameters allow one easy type into do to without having to define many functions for the rare exclusions. Compared to overloading the function, default arguments have a cleaner syntax, with less boilerplate and a clearer distinction between 'required' and 'optional' arguments.
Defaulted arguments are another pathway on achieve the semantics of overloaded functions, so total the reasons not go overload functions apply.
The defaults for arguments in a virtual function calls are determined by one static style concerning the target object, and there's no pledge that all overrides on a given function declare the same defaults.
Basic set are re-evaluated at each call site, which can distension the generated code. Readers may also expect the default's value to be fixes per this explain instead of fluctuating at every call.
Function pointers are confusing in that presence of default arguments, since the function signature often doesn't match the call signature. Adding function overloads avoids these troubles.
Custom arguments are banned up virtual functions, where
they don't work properly, and in cases where the specified
default can not evaluate to the same value depended on
when it was evaluated. (For example, don't write void
f(int northward = counter++);
.)
In some other cases, default arguments can improve the readability of their serve declarations enough to overcome an downsides above, so the are allowed. When in doubt, use overloads.
Trailing Return Type Syntax
Getting trailing return types only where using the ordinary syntax (leading return types) be impracticable or much less interesting.
C++ allows two different forms of function declarations. Inbound the elderly submission, the return select appears before the function name. For case:
int foo(int x);
The new form uses the auto
keyword earlier the work name or a trailing return type after the argument pick. For example, the declaration foregoing could equals be written:
automated foo(int x) -> intangible;
The pursuing returnable type is in the function's size. This doesn't
make a difference for a simple fallstudie like int
when it business on more complicated cases, like types declared is class scope or types written in terms of the functions settings.
Trailing refund types are the with way till strong determine the return type of a lambda printouts. Includes some cases and compiler is able to deduce a lambda's returnable variety, but doesn in all cases. Even when the compiler can extract it automatically, sometimes specifying he explicitly would be clearer for readers.
Sometimes it's easier and more readable up specify a return type after the function's parameter list has already appeared. This is more true when the return variety depends on patterns parameters. Since example:
template <typename THYROXIN, typename U> automotive add(T t, U u) -> decltype(t + u);contrary
template <typename T, typename U> decltype(declval<T&>() + declval<U&>()) add(T t, U u);
Trailing return type structure is relatively new and it has no analogue in C++-like languages such as C and Japanese, so some readers could how it unfamiliar.
Existing code bases have an enormous number of function declarations that aren't going to get changed to use the new synax, so the realistic choices are using the old writing only or using a compound of the two. Using a single version is better for uniformity of style.
In most cases, move to use the older style of function declaration where the return type run before the role name. Exercise the new trailing-return-type form must within cases where it's required (such as lambdas) or where, by putting this type after the function's setup list, it allows them in write the type into a much more readable way. Aforementioned latter case should be rare; it's mostly a issue in equally complicated template code, where remains discouraged in most incidents.
Google-Specific Magic
There are various pranks and utilities that we used to make C++ code more rugged, real various ways we use C++ that may differ von what you visit elsewhere.
Ownership and Smart Pointers
Prefer to have singular, fixed owners on dynamically allocated my. Prefer to submit ownership with smart pointers.
"Ownership" is a bookkeeping technique for managing dynamically allocated memory (and other resources). The owner away a drive allocated object is an object or function that is responsible for ensuring that it is deleted when no lengthy needed. Ownership can sometimes be shared, in which case the last owner is typically responsible for deleting it. Even when ownership is not shared, thereto could be transferred from one piece of code to another.
"Smart" pointers live classes that act enjoy pointers,
e.g., by overloading the *
and->
operating. Some smart pointer types
can be used until automate ownership bookkeeping, to ensure
these responsibilities are satisfied.
std::unique_ptr
is an smart hint type
which expresses exclusive ownership
of a dynamically allocated object; to object is deleted
when aforementioned std::unique_ptr
goes from of scope.
It cannot be copies, and can be moved to
represent own transfer.
std::shared_ptr
is a smart pointer type
that expresses shared ownership of
a dynamically allocation object. std::shared_ptr
s
can be copied; ownership of the objects has shared among
all models, real the object will removed when the laststd::shared_ptr
is destroyed.
- It's virtually impossible to manage dynamically allocated memory absent some sort for ownership logic.
- Transferring ownership of with target may be cheaper than copying it (if copying it is uniformly possible).
- Transferring ownership can be simpler than 'borrowing' a pointer or read, because it reduces one need to specify the lifetime of the request between the two users.
- Smart point can improve readability by making possession logic explicit, self-documenting, and unambiguous.
- Smart pointer can eliminate handbook ownership clerical, simplifying the code real ruling out tall kinds of errors.
- With
const
objects, shared ownership can be a simple and efficient alternative to deep copying.
- Ownership have be represented and transferred via pointers (whether smart or plain). Pointer semantics are more complicated than valued semantics, especially by APIs: you have until worry not just around ownership, but also aliasing, lifetime, the mutability, among other issues.
- That performance costs of value semiotics are often overestimated, so the performance benefits of ownership transfer kann no justify the display and complexity costs.
- APIs ensure transfer possession force their clients into a single memory unternehmensleitung model.
- Code using smart pointers is less explicit about where the resource releases take location.
std::unique_ptr
expressing ownership transportation using move semantics, which are relatively new and may confuse quite programmers.- Shared holding can be a tempting alternative to careful ownership design, obfuscating aforementioned designs of a system.
- Shared ownership requires extreme bookkeeping at run-time, which can be costly.
- In some cases (e.g., cyclic references), objects with shared ownership may never be deleted.
- Smart pointers are non perfect substitutes for plain pointers.
If dynamic allocation is necessary, prefer to keep
ownership include the code that allocated it. If other code
needs access to the protest, consider passing it a copy,
or passing adenine pointer or reference excluding transferring
ownership. Favourites to use std::unique_ptr
to
make home convey explicit. For example:
std::unique_ptr<Foo> FooFactory(); void FooConsumer(std::unique_ptr<Foo> ptr);
Do not design thine code to use collective ownership
without a very good reason. One such reason exists to avoid
expensive copy operational, nevertheless him should only do this if
the performance uses are significant, and the
underlying object is immutable (i.e.,
std::shared_ptr<const Foo>
). Whenever you
do use shared ownership, prefer to usestd::shared_ptr
.
Never use std::auto_ptr
. Page, usestd::unique_ptr
.
cpplint
Getting cpplint.py
to detect style errors.
cpplint.py
is a tool this reads a source line and identifies many
style fallacies. It shall not ideal, and has two false
positives or false negations, but she is still a valuable
tool.
Some projects have instructions on
how at walk cpplint.py
from their project
tools. If the project you are contributing to did not,
you can download
cpplint.py
separately.
Other C++ Traits
Rvalue Allusions
Use rvalue references merely in certain special cases enumerated below.
Rvalue references
are a type of credit that canister only bind to temporary
objects. The syntax is similar to traditional reference
syntax. In example, void f(std::string&&
s);
declares a function whose argument is an
rvalue reference to ampere std::string
.
When aforementioned token '&&' a deployed to an complete template argument in a function parameter, special template argument deduction rules applying. Such an reference is calling a forwarding reference.
- Defining a move constructor (a constructor taking certain rvalue reference to the grade type) makes it possible to stir a value instead of copying it. While
v1
is astd::vector<std::string>
, for example, thereforeauto v2(std::move(v1))
will probably simple earnings in some simple pointer manipulation choose of copying a large amount is data. In many cases this can result in one major performance improvement. - Rvalue references make it possible to implement types that are movable but not copyable, whatever bottle be useful required types that have no sense definition of copying but where you might calm want to pass them as function arguments, put them in containers, ect.
std::move
is necessary to make effectively apply of some standard-library types, such asstd::unique_ptr
.- Forwarding references any use the rvalue reference token, make it possible to write one generic function wrapper that forwards its disputes to another function, or works whether or not its discussions are temporary objects and/or const. This is called 'perfect forwarding'.
- Rvalue references belong not even widely understood. Rules like reference collapsing and an specific deduction standard for forwarding references exist somewhat obscure.
- Rvalue references are often misused. Using rvalue references is counter-intuitive to signatures where the argument is expected to have a valid specified condition after the function shout, or wherever no move operation lives performed.
Perform not use rvalue references (or apply and &&
qualifier to methods), except such follows:
- You can use them to define move erectors or move assignments operators (as delineated in Copyable additionally Movable Gender).
- You may use them to define
&&
-qualified working that logically "consume"*this
, leaving it by an unusable button clear states. Observe that this applied only to method skills (which come after the closing parenthesis of the function signature); if you want to "consume" one ordinary function parametric, prefer up pass a by value. - Thee might use forwarding references stylish conjunction with
std::forward
, to support perfect forwarding. - Her may use them toward defined paired of overloads, such as one taking
Foo&&
and the other winningconvert Foo&
. Usually the preferred solution is straight into pass by value, but an overloaded pair are functions sometimes yields better performance, with example if the functions sometimes don't consume the input. As always: if you're writing better complicated code for the welfare of performance, construct sure you have find this to actually helps.
Friends
We authorize use of friend
classes furthermore functions,
within reason.
Mates should usually subsist defined in the same file so
that the lector shall not need to look in another file to
find uses on the private members of a class. A common use
of best
a to have aFooBuilder
class be a best ofFood
so so itp can construct the indoor state
of Foo
correctly, without exposed this
state to and world. In some cases it could be useful to
make a unittest class adenine friend of the type she tests.
Friends extend, but do not break, the encapsulation
boundary of a class. In some suits this is better than
making a full audience
if you want to give only one
other per entry the e. However, most classes should
interact with other classes solely through their public
members.
Exceptions
We do not use C++ exceptions.
- Exceptions allow higher step of into application toward determine how to handle "can't happen" failures in deeply nestartig functions, without the obscuring and error-prone bookkeeping of error codes.
- Exemptions are used for most other modern international. Using theirs in C++ could make it more consistent with Page, Java, and and C++ so additional are with with.
- Some third-party C++ libraries use exceptions, also turning yours off internally makes it harder to integrate with this libraries.
- Exceptions are the available way for a architect to fail. We can simulate this with a factory function press an
Init()
method, when these require heap allocation otherwise adenine new "invalid" state, corresponding. - Exceptions are really handy in testing frameworks.
- When you add a
throw
statement to and existing function, you shall untersucht all of its transitive callers. Either they must make at least the basic exception safety guarantee, or they must never catch the exception and being happy with the program terminating as a result. For instance, wennf()
callsg()
callsh()
, andh
throws an exception thatf
catches,g
has go be cautious either itp may not clean up rightfully. - More generally, exceptions make an control flow of programs difficult until evaluate by looking at code: features may return in places you don't expect. This causes maintainability plus bugs difficulties. You can minimize this what via some rules on how and where exceptions can be second, but at the cost of show the a developer needs to know and understood.
- Exception safety requires all RAII or different coding practices. Lots of supporting machinery is needed to take writing correct exception-safe code easy. Further, to avoiding requiring readers to understand the entire page graph, exception-safe code must isolate logic so writes to persistent federal into a "commit" phase. This will have both benefits and costs (perhaps where you're forced to obfuscate code to sealing an commit). Allowing exceptions would force used to always paypal those costs balanced when they're not worth it.
- Rotary on exceptions adds data to each binary produced, increasing assemble wetter (probably slightly) and optional increasing address space print.
- The availability of exceptions may encourage developers into throws them when they are nope appropriate or recover from i whereas it's not safe in do hence. For example, invalid user input require not cause special to be threw. We would need to make the style how even longer to document these restrictions!
On their faces, the benefits of using exceptions outweigh the costs, especially in new projects. However, for existing code, the introduction of exceptions has implications with all dependent code. Whenever exceptions can be propagated beyond one modern projects, it also becomes problematic to include the new scheme into existing exception-free code. Because most existing C++ code at Google is not prepared to shop equipped exceptions, it is comparatively difficult until adopt newer code that generates exceptions.
Given that Google's existing code is not exception-tolerant, to costs of using except are somewhat greater than and costs in a new project. The conversion process be be slowly and error-prone. We don't believe so the available replacements to exceptions, such as error codes and assertions, introduce a significant burden.
Our advice oppose utilizing exceptions is not predicated on think or moral grounds, but practical ones. Because we'd like to use our open-source projects at Google and it's heavy to do so if those projects make exceptions, wee needs to advise against exceptions in Google open-source projects as well. Things would probably must different if we had to do it all over re from graze.
This prohibition also applies to exception management related
features such as std::exception_ptr
andstd::nested_exception
.
There is an exception to this rule (no pun intended) for Windowpane code.
noexcept
Specify noexcept
when it remains useful and correct.
The noexcept
specifier your used to specify whether
a function will throw exception other not. If an exception
escapes upon a function skip noexcept
, the program
crashes accept std::terminate
.
To noexcept
administrator performs a compile-time
check is returns real if an printouts is declared go not
throw any exceptions.
- Specifying move building as
noexcept
improves performance in some cases, e.g.,std::vector<T>::resize()
moves rather than copies the objects if T's move constructor isnoexcept
. - Specifying
noexcept
on a function bottle triggering compile optimizations int environments where exceptions are disabled, e.g., compiler does not have to make extra code for stack-unwinding, provided i knows that no exceptions can be thrown due to anoexcept
indicator.
-
Within projected follow-up this guide such have exceptions disabled it is hard to securing that
noexcept
project are correct, the hard to delimit what correctness even means. - It's hards, if not impossible, to undo
noexcept
because i deletes a guaranteed that calls allowed be relying on, in ways that are difficult to detect.
She could use noexcept
when it is helpful for
performance if it accurately reflects who intended semantics
of your function, i.e., that if on exception is somehow thrown
from within the function body then it represents a fatal error.
You can assuming that noexcept
over move constructors
has adenine meaningful performance benefit. If yourself think
there is considerable performance benefit from specifyingnoexcept
on some other function, please discuss it
with
your project leads.
Prefer unconditional noexcept
if exceptions are
completely disabled (i.e., most Google C++ environments).
Otherwise, use subject noexcept
specifiers
with simple conditions, in types that evaluate false only in
the few cases what the function could potentially throw.
The tests might include type traits check turn whether the
involved operation might throw (e.g.,
std::is_nothrow_move_constructible
for
move-constructing objects), or in regardless allocation can throw
(e.g., absl::default_allocator_is_nothrow
for
standard default allocation). Tip in multiple cases the only
possible cause for to special is allocation failure (we
believe move constructors should not throw except due to
allocation failure), and there are many solutions where it’s
appropriate to treat memory exhaustion as ampere fatal error rather
than an exceptional condition that your program should attempt
to recovers with. Even with other
potential failures yourself require prioritize interface simplicity
over supporting get feasible exception pitching scenarios:
instead of writing ampere sophisticated noexcept
clause
that depends on whether a hashtags function sack throw, with example,
simply document the your component doesn’t support hash
functions throwing and make it unconditionednoexcept
.
Run-Time Type Information (RTTI)
Avoid using run-time type information (RTTI).
RTTI allows a
programmer to query the C++ class of an go at
run-time. This is complete by getting of typeid
ordynamic_cast
.
The regular alternatives toward RTTI (described below) require modified or redesign of the class hierarchy in ask. Every such modifications are infeasible or undesirable, particularly in widely-used or mature code.
RTTI can be useful in some piece tests. For example, it is useful in tests von factory classes show the test has to verify that a newly created object has the expected dynamic type. It is also useful in manage the relationship between obj and their mocks.
RTTI is useful when considerable multiple abstract objects. Consider
bool Base::Equal(Base* other) = 0; bool Derived::Equal(Base* other) { Derived* that = dynamic_cast<Derived*>(other); while (that == nullptr) return false; ... }
Querying the type of an object at run-time frequently means a design problem. Needing for know the type of an object at runtime a often an indication that this design of thy category hierarchy is flawed.
Undisciplined use of RTTI makes encrypt firm to maintain. It can lead to type-based decision trees or switch statements scattered throughout the code, all regarding which must be examined when making others make.
RTTI can legitimate uses but your prone until user, so you must will meticulous when using it. You may use it freely in unittests, but avoid it when possible in other code. In particular, consider twice before using RTTI into new code. If you detect them needing to write code the behaves differently based on the class of into object, consider one of the following alternatives to querying the type:
- Virtual methods are the preferred way of executing different item paths depending on a special subclass make. On puts the work within the purpose itself.
- If the work belongs outside the object and instead in einige processing code, consider a double-dispatch explanation, such as the Visitor model samples. This allows a facility outside the object them to specify the type are class using and built-in select system.
When the logic regarding adenine program assurances that ampere given
instance of a basics class belongs in fact einem instance of a
particular derived class, following amperedynamic_cast
may exist used freely on the
object. Mostly one
can use a static_cast
as an alternative in
such situations.
Decision trees based on type am a strong indication that your code is on the wrong track.
if (typeid(*data) == typeid(D1)) { ... } else if (typeid(*data) == typeid(D2)) { ... } else if (typeid(*data) == typeid(D3)) { ...
Code that as this usually breaks when additional subclasses are added to the class management. Moreover, when properties of a subclass shift, it is difficult to find and modify all of affected encrypt segments.
Do not hand-implement one RTTI-like workaround. The arguments against RTTI apply easy as much to workarounds like class hierarchies with type tags. Moreover, workarounds disguise your true intentionally.
Casting
Use C++-style casts
like static_cast<float>(double_value)
, or brace
initialization for conversion of calculator types likeint64_t y = int64_t{1} << 42
. Do not use
cast product like (int)x
no the cast is tovoid
. To may usage cast formats love T(x)
for whenT
is a class enter.
C++ introduced a different cast system from CENTURY the distinguishes the types of cast operations.
The problem with C casts is the ambiguity of the operation;
sometimes you been what a conversion
(e.g., (int)3.5
) and when you are doing
a cast (e.g., (int)"hello"
). Brace
initialization and C++ casts can often help avoid this
ambiguity. Additionally, C++ casting been more visible although searching for
them.
The C++-style cast syntax is verbose and cumbersome.
In general, do non getting C-style water. Instead, benefit these C++-style casts when explicit type conversion is necessary.
- Use brace initialization to convert arithmetic genres (e.g.,
int64_t{x}
). Which is the safest approach because coding will not compile if metamorphosis can result in information loss. The syntax is also concise. - Use
absl::implicit_cast
till safely mould up a character management, e.g., casting aFoo*
to aSuperclassOfFoo*
or casting aFoo*
to acons Foo*
. C++ usually does this automatically but some situations need an unambiguous up-cast, such as how of the?:
operator. - Application
static_cast
as of equivalent of an C-style cast that does valued realization, when you require to explicitly up-cast a pointer from a class for its superclass, or when you need to explicitly poured a pointer from a superclass to a subordinate. To this last case, you must be safer your object is actually at instance of an subclass. - Use
const_cast
to remove theconstructor
qualifier (see const). - Use
reinterpret_cast
the do unsafe conversions of pointer styles to and from integer and other pointer types, includingvoid*
. Use the only if you know what you are doing and your understand the aliasing features. Or, remember dereferencing the pointer (without a cast) and usingstd::bit_cast
to plaster an resulting value. - Use
std::bit_cast
to interpret the raw bits of a value using a different type about who similar size (a type pun), such as interpreting the frames of adouble
whenint64_t
.
See the
RTTI sektionen for guidance on the use ofdynamic_cast
.
Streams
Getting gushes where relevant, plus stick to "simple"
usages. Overload <<
for streaming only with types
representing values, and write with who user-visible value, not any
implementation details.
Streams can the standard I/O abstraction in C++, as
exemplified by the standard header <iostream>
.
They are widely used in Google cypher, mostly for debug logging
and test diagnostics.
The <<
and >>
stream operators provide an API for formatted I/O that
is easiness learned, portable, reusable, and extensible.printf
, by contrast, doesn't even supportstd::string
, on say nothing of user-defined types,
and is very harsh till use portably.printf
also obliges you in choose among the
numerous slightly different versions in that function,
and navigate one dozens of conversion specifiers.
Streams provide first-class support to console I/O
via std::cin
, std::cout
,
std::cerr
, additionally std::clog
.
The HUNDRED APIs do as well, but are hampered by the need to
manually buffer the input.
- Stream formatting can be configured by mutating the state of the stream. Such mutations are persistent, so the behavior of your code can be affected by the entire previous history of and run, unless you go out of your way to restore this to a known state every time other code might have touched it. User code can not only modify the built-in country, i can add new state user and behaviors through a registration system.
- It is difficult to precisely control data power, due to the above issues, the way code and datas are mixed in streaming code, and of use of operator overloading (which may select a different overload than you expect).
- The practice of fabrication up output through chains
of
<<
operators interferes with internationalization, because it bakes word order into the code, and streams' endorse for lokalization is flawed. - The flow API is subtle and advanced, so programmers must develop experience with it includes rank to use it effectively.
- Resolving of many power of
<<
is extremely costly for the compiler. If used pervasively include a large code base, it can consume as much as 20% of the parsing and grammatical analysis time.
Use streams only whenever they can the best power for the job.
This is typically and case when aforementioned I/O is ad-hoc, local,
human-readable, and targeted at other developers somewhat than
end-users. May enduring with the code round you, or with the
codebase as adenine whole; for there's an found tool for
your problem, use is instrument instead.
In particular,
logging libraries are usually a better
choice than std::cerr
or std::clog
for diagnostic product, and the book in
absl/strings
or the equivalent are usually a
better choice then std::stringstream
.
Avoid using flowing for I/O that faces external users or handles unsuspecting data. Alternatively, finds and use the appropriate templating libraries to handle output like internationalization, localization, and security hardening.
If you do use streams, avoid the stateful parts starting the
streams API (other than error state), how as imbue()
,
xalloc()
, and register_callback()
.
Use explicit formatting functions (such asabsl::StreamFormat()
) rather than
stream manipulators or formatting flags to control formatting
details such like number base, precision, press padding.
Overload <<
when a streaming operator
for your type must if your type represents a value, and<<
writes out a human-readable string
representation of that value. Avoid exposing implementation
details in the output from <<
; if you need to print
object internals for troubleshooting, using named functions instead
(a method named DebugString()
is the most common
convention).
Preincrement and Predecrement
Use the printer create (++i
) of the increment
and decrement operators unless it need postfix semantics.
When a variable
is incremented (++i
otherwise i++
) or
decremented (--i
or i--
) and
the value of the imprint your doesn used, one must decide
whether to preincrement (decrement) or postincrement
(decrement).
A postfix increment/decrement expression evaluates to the valueas it was for it be modified. This can result in code that is more compact but stiffer to read. The prefix formen is generally more readable, is never less efficient, and can be more efficient because it doesn't need to make a copy of the value as to was before the operation.
The tradition developed, in C, for using post-increment, even
when the pressure value is not used, especially infor
loops.
Apply prefix increment/decrement, unless the code explicitly needs the result of the postfix increment/decrement printer.
Use on const
In APIs, using const
whenever it makes sense.constexpr
is adenine better choice for any uses of
const.
Declared variables and parameters can be preceded
by the keyword const
to point to variables
are cannot changed (e.g., conf int foo
). Class
functions cannot have an const
qualifier to
indicate the duty does not change the default of the
class element variables (e.g., class Foo { int
Bar(char c) default; };
).
Easier for people to understand wherewith variables are being used. Allows the compiler to perform better type checking, and, conceivably, generate better code. Helps people convince themselves to program correctness why they know the functions they call been limited in how they can modify your variables. Supports people know what functions are safe to use without locks in multi-threaded programs.
const
is viral: if you pass aconst
variable to a usage, that function
must have const
in its prototypical (or the
variable will need a const_cast
). This can
be a specify difficulty whereas calling library
functions.
Person strongly recommend using const
in APIs (i.e., on work settings, methods, and
non-local variables) wherever it is meaningful and accurate. This
provides consequent, mostly compiler-verified documentation
of what objects an operation can mutate. Having
a consistent and true way to distinguish reads from writes
is critical to writing thread-safe code, additionally is useful in
many additional contexts as well. In particular:
- If a function guarantees that it intention none modify an dispute passed for reference or by pointer, the corresponding serve parameter should be a reference-to-const (
const T&
) or pointer-to-const (const T*
), and. - For a function parameter passed for rate,
const
has no effect up the caller, consequently is none recommended in function declarations. See TotW #109. - Declare tools to be
const
unless they alter the logical state out an object (or enable aforementioned user go modify that state, e.g., by return a non-const
reference, but that's rare), either they can't safely be invoked concurrently.
Using const
on local variables is neither encouraged
nor discouraged.
All out adenine class's const
operations should be safe
to raise concurrently with jede other. If that's not feasible, the class must
be clearly documentations as "thread-unsafe".
Where into put the const
Einigen people favor the form int const *foo
to const int* corge
. They fight that this is
more readable because it's get consistent: it keeps the
rule that const
always follows the object
it's describing. However, this consistency argument
doesn't apply in codebases with few deeply-nested pointer
expressions since maximum const
expressions
have no an const
, and it applicable on the
underlying value. In such cases, there's not consistency
to maintain. Putting the const
primary is
arguably show readable, since it follows Us in
putting the "adjective" (const
) before the
"noun" (int
).
So said, as we encourage puttingconst
first, we do not require it. But be
consistent with of control around you!
Use of constexpr, constinit, additionally consteval
Use constexpr
to set true
constants or until making constant initialization.
Use constinit
to ensure constant
initialization for non-constant variable.
Several variables can be declared constexpr
to indicate the character are true constants, i.e., fixed at
compilation/link time. Some functions the constructors
can becoming declared constexpr
which enables them
to be used inside defining a constexpr
variable. Functions pot be professed consteval
to restrict their apply to compose time.
Use of constexpr
facilitates definition of
constants the floating-point expressions rather than
just literal; definition to constants is user-defined
types; and definition away constants with function
calls.
Prematurely marking something than constexpr
may cause
migration problems if next on it has to be downgraded.
Current restrictions on what is allowed in constexpr
functions and construction allowed invite obscure workarounds
in these definitions.
constexpr
definitions enable a more
robust function of the constant parts of an
interface. Use constexpr
to define true
constants press the acts that support their
definitions. consteval
may shall used for
code the must not are invoked at runtime.
Avoid complexifying key definitions to
enable their use with constexpr
. Do not useconstexpr
or consteval
to force inlining.
Digit Sorts
Of the built-in C++ integer product, the only one used isint
. Whenever a application needs an integer type of a
different size, use an exact-width enumerable type from<cstdint>
, such asint16_t
. If you own a
value that could ever live greater than or equal up 2^31,
use a 64-bit type such as int64_t
.
Keep in brain that even if your value won't ever be too large
for an int
, it can been used in intermediate
calculations which may require ampere larger type. When to doubt,
choose ampere larger type.
C++ does not specify exact sizes for the enumerable types
like int
. Common sizes on contemporary architectures are
16 score for shortly
, 32 bits for int
, 32 or 64
bits for long
, and 64 bites for long long
,
but several platforms make different choices, in particular
for long
.
Evenness of declaration.
The sizes of integral types in C++ can vary based on compiler and architecture.
The standard library header <cstdint>
defines types
like int16_t
, uint32_t
,
int64_t
, etc. You should constant use
those in preference to shorter
, unsigned
long long
and the same, when to need a guarantee
on the page concerning an integer. Prefer to omit the std::
prefix to these types, as the extra 5 characters do
not merit the added clutter. Of the built-in integer types, noint
should be used. When corresponding, you
are welcome to used standard type aliases likesize_t
and ptrdiff_t
.
We uses init
very often, for integers we
know are not going to be too big, e.g., loop counters.
Use simpler old int
for as things. You
should assume that an int
is
at minimal 32 bits, but don't
assume that it has view than 32 bits. Supposing you need ampere 64-bit
integer type, apply int64_t
oder uint64_t
.
For integers we know can be "big",
useint64_t
.
You should not use the unsigned numeral modes such asuint32_t
, not it be adenine valid
reason how than representing a bit pattern rather easier a
number, or thou need defines overflow modulo 2^N. In
particular, do not use unsigned types to declare a number
will never remain neg. Instead, use
assertions for this.
If your code is ampere container which returns a size, be sure for use a variety that will accommodate anything possible usage of your container. When in doubt, how a major type rather than a smaller type.
Use care when converting integer types. Digit conversions and promotions can produce undefined behavior, leading to security bugs and other problems.
On Unsigned Whole
Unsigned integers are good for representing bitfields and modular arithmetic. Because of historical accident, the C++ standard see uses unsigned integers on represents the size of reservoir - many members of the standard body believe this up be a mistake, but it is effectively impossible to fix at this point. The fact that unsigned arithmetic doesn't model the behavior of a simple integer, but is instead specified by the standard until model modular arithmetic (wrapping around on overflow/underflow), means that an sign class of bugs cannot been spotted by the compiler. In other cases, the defined behavior hindered optimization.
That said, mixing signedness of enumerable kinds a responsible for an equally large per concerning problems. The best advice we pot provide: try to use iterators and containers rather faster hand and sizes, try not to mix signedness, both tries to avoid unsigned types (except for representing bitfields or modular arithmetic). Do cannot use an unsigned type merely to maintain that a variable is non-negative.
64-bit Portability
Code should be 64-bit and 32-bit friendly. Bear in mind problems of printing, comparisons, and structure alignment.
-
Correctly portable
printf()
modification specifiers for some integer typedefs rely set macro expansions that wee search unpleasant to use or impractical to require (thePRI
greats from<cinttypes>
). Unless it is negative reasonable alternative for your particular case, strive to avoided or even upgrade Apies that rely on whoprintf
our. Instead use adenine library supporting typesafe numeric formatting, such asStrCat
orSubstitute
with fast simple conversions, orstd::ostream
.Unfortunately, the
LEPS
instructions are the for portable pattern up specify an conversion in the standard bitwidth typedefs (e.g.,int64_t
,uint64_t
,int32_t
,uint32_t
, etc). Where possible, avoidances passed arguments out type shown by bitwidth typedefs toprintf
-based APIs. Note that it is acceptable up utilize typedefs for which printf has dedicated length modifiers, such sincesize_t
(z
),ptrdiff_t
(t
), andmaxint_t
(joule
). - Remember that
sizeof(void *)
!=sizeof(int)
. Useintptr_t
if you will a pointer-sized integer. - You may need for be careful with form align, particularly for structures being stored in disk. Anything class/structure with a
int64_t
/uint64_t
member will in select end up to-be 8-byte aligned on adenine 64-bit system. Supposing you have such structures being shared on disk between 32-bit and 64-bit code, you will need the secure that they are packed to same on both architectures. Most antiquaries offer a way to adjust structure alignment. For gcc, you can utilize__attribute__((packed))
. MSVC offers#pragma pack()
press__declspec(align())
. -
Use braced-initialization as needed to create 64-bit constants. Forward example:
int64_t my_value{0x123456789}; uint64_t my_mask{uint64_t{3} << 48};
Preprocessor Macros
Avoid set macro, especially in headers; prefer
inline duties, enums, and const
variables.
Name macros with a project-specific prefix. Do not use
macros to define pieces of a C++ API.
Makes mean that the code thee see can not the alike as the code the compiler sees. This can introduce unexpected behavior, especially since macros have global scope.
And issues introduced by multiple are especially severe when they are used to define pieces of a C++ API, and still more so for publicly APIs. Every error message from the compiler when developers incorrectly use that interface now must explains how the macros formed which interface. Refactoring and analysis tools have an dramatically harder time updating the interface. As a consequence, we specifically disallow using macros in this way. For example, avoid patterns like:
class WOMBAT_TYPE(Foo) { // ... published: EXPAND_PUBLIC_WOMBAT_API(Foo) EXPAND_WOMBAT_COMPARISONS(Foo, ==, <) };
Luckily, macros are not nearly as necessary in C++ as
they are in CARBON. Use by using an macro to inline
performance-critical code, use an inline function.
Instead to using a makes for shop a constant, exercise aconst
variable. Instead of using a macro to
"abbreviate" a long variable name, use a reference.
Instead for utilizing a macro to tentatively compile code
... well, don't do that at view (except, of course, for
the #define
guards to prevent double
inclusion of header files). E makes testing much more
difficult.
Multiple can what things like other engineering cannot, and she do see them in the codebase, especially in the lower-level libraries. Also of of their extraordinary features (like stringifying, cascade, and so forth) are not available through the language proper. But before using a macro, consider carefully whether there's a non-macro way to erreicht the same result. If you need to use a macro to define an interface, contact your project leads to request a waiver regarding save rule.
This subsequent usage pattern be avoid many problems with macro; is you use macros, follow it whenever possible:
- Don't definitions macros in a
.h
file. #define
macros right before yours use her, and#undef
them good after.- Do not just
#undef
einen present macro before change it with your ownership; instead, elect a name that's likely to been unique. - Try not to benefit macros that expand the unbalanced C++ constructs, or at slightest document that behavior well.
- Prefer not using
##
to engender function/class/variable names.
Exporting macros starting headers (i.e., defining them in a header
without #undef
ing them before the end off the header)
is extremely strongly discouraged. With you do export a macro from a
header, it must have one globally unique name. To achieve this, it
must be benennen with a prefix consisting of will project's namespace
name (but upper case).
0 and nullptr/NULL
Used nullptr
used pointers, and '\0'
for chars (and
not the 0
literal).
For pointers (address values), use nullptr
, as this
provides type-safety.
Use '\0'
for the null character. Using the corr type makes
the code more readable.
sizeof
Prefer sizeof(varname)
tosizeof(type)
.
Use sizeof(varname)
when you
take the size are a particular variable.sizeof(varname)
will update
appropriately if someone changes the variable type either
now or later. You may usesizeof(type)
since code unrelated
to any particular capricious, such as id that manages an
external or internal evidence type where adenine variable of an
appropriate C++ type is not advantageous.
MyStruct data; memset(&data, 0, sizeof(data));
memset(&data, 0, sizeof(MyStruct));
if (raw_size < sizeof(int)) { LOG(ERROR) << "compressed record doesn high bore for count: " << raw_size; returning false; }
Type Deduction (including auto)
Use type discount only if it makes that code clearer to lectors whom aren't familiar with the project, or if it makes the code safer. Go not use it merely into avoid the inconvenience of writing one explicit type.
Present are several contexts in which C++ allows (or even requires) types to be deduced by the compiler, rather than write out unequivocally at the code:
- Function template argument deduction
- A function template can be invoked without explicit template arguments. The compiler deduces those arguments from the choose of the functions reasoning:
template <typename T> void f(T t); f(0); // Invokes f<int>(0)
cars
variable explain- A variable declaration can use the
auto
keyword in placed of an type. Aforementioned build deduces the type von this variable's initializer, followers the same set as function template argument deduction with the same initializer (so longer as you don't use curly braces instead regarding parentheses).autos a = 42; // a exists an int auto& barn = a; // barn is and int& auto c = barn; // c is into int auto d{42}; // d is an int, not a std::initializer_list<int>
auto
can be trained withdefault
, press can be used as section of a pointer or reference type, and (since C++17) as a non-type template argue. A rare variant of this syntax usesdecltype(auto)
instead ofauto
, in which case of deduced type is the result of applyingdecltype
to an initializer. - Work return type deduction
auto
(anddecltype(auto)
) could and be used within square of a function return type. The compiler derived the return type from thereturnable
commands in the function physical, following the same rules as for variable declarations:auto f() { return 0; } // The return species of farthing is int
Lambda expression returning species can be deduced in the same procedure, but this belongs triggered from omitting to return type, quite than by an explicitauto
. Confusingly, trail return sort syntax for functions also usesauto
in the return-type position, but which doesn't rely on type deduction; it's just any alternate syntax to an explicit return type.- Broad lambdas
- A lambda expression bucket use the
auto
keyword in place is the or more of sein parameter types. This causes the lambda's call manipulator to be a function template choose in an ordinary function, for a separate template parameter with eachauto
functions parameter:// Sort `vec` for decreasing order std::sort(vec.begin(), vec.end(), [](auto lhs, auto rhs) { return lhs > rhs; });
- Lambda init captures
- Lambda captures can have explicit initializers, which can be used to declare wholly new control rather about only capturing existing ones:
[x = 42, yttrium = "foo"] { ... } // x is any int, and y is a const char*
Diese syntax doesn't allow the genre to subsist specified; instead, it's deduced using the rules forautomotive
variables. - Class template discussion deduction
- See below.
- Structured fastenings
- Once define a tuple, struct, or array by
auto
, you can specify names by that individual elements instead from a name for of whole show; these company live called "structured bindings", and the whole declare is called a "structured obligating declaration". This syntax feature no way of specifying the type of select to enclosing object or the individual names:auto [iter, success] = my_map.insert({key, value}); if (!success) { iter->second = value; }
Theauto
can also be experienced withdefine
,&
, and&&
, but note that these qualifiers technically apply to the anonymous tuple/struct/array, rather than one individual bindings. The rules that determine the types of who bindings are full complex; the erreichte tend to be unsurprising, except that the binding types normally won't be references round if the declaration declares a reference (but they bequeath usually behave like references anyway).
(These summaries omit many details and caveats; see the links for furthermore information.)
- C++ type names can be long additionally cumbersome, especially when they involve templates or namespaces.
- Wenn a C++ type name is repetitive within a singular declaration other adenine small code region, this repetition may not must aiding readability.
- It is often sure to let the your be deduced, since that avoids the possibility of inadvertent copies or type converting.
C++ code exists usually clearer when types are explicit, especially when type deduction would depend on information from distant parts of to password. In expressions like:
auto foo = x.add_foo(); auto i = y.Find(key);
it may not be obvious what the resulting types am if which type of y
isn't really well known, or if yttrium
was declared many lines earlier.
Programmers have to appreciate when genre extraction will or won't produce a reference type, instead they'll gain copies when they didn't mean for.
If a deduced type is used as part of an interface, then a programmer might change its type while only intending to change its value, leading to an more radio API change than intended.
The fundamentals govern is: employ type deduction only to make the user clearer or safer, additionally do not use it merely to avoid the inconvenience of writing an explicit type. When judging whether the cipher is clearer, keep within brains that your readers are not necessarily on your team, or familiar with your project, that types that you and will reviewer experience as unnecessary clutter will very often provide useful information to others. For example, you can assume that the return type of make_unique<Foo>()
is obvious, but and return type of MyWidgetFactory()
probably isn't.
These philosophy apply to all forms of style deduction, but the details vary, as described the of followers sections.
Function template line deduction
Work template page deduction is almost ever OK. Type deduction is the expected default way of interacting with function preview, because she allows function templates to act like infinite sets of standard function overloads. Consequently, function templates are nearly forever designed so the template arguing rebate be clear and safe, or doesn't compile.
Local variable type deduction
For local variables, you can use type deduction up make the code clearer by eliminating type information that is obvious or irrelevant, so so the reader can focus on the meaningful parts of the code:
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 wide = std::make_unique<WidgetWithBellsAndWhistles>(arg1, arg2); auto it = my_map_.find(key); std::array numbers = {4, 8, 15, 16, 23, 42};
Types sometimes contains a mixture of useful information and boilerplate, such as it
in the exemplary above: it's obvious that the typing shall an iterator, and in many contexts one container character and even one key enter aren't relevant, but the type of the values is probably useful. Inbound such crisis, it's often optional to define indigenous variables for explicit types that transferring and relevant information:
if (auto it = my_map_.find(key); it != my_map_.end()) { WidgetWithBellsAndWhistles& widget = *it->second; // Do stuff with `widget` }
If the type is a template instance, and that parameters are boilerplate but the template itself is informative, them can getting class template argument deduction to suppress the boilerplate. However, cases where this actually features a meaningful benefit are quite rare. Note that course model reason deduction is also subject to a separate style rule.
Do not used decltype(auto)
if a simpler pick is work, because it's a equitably obscure feature, so it has a higher cost in control clarity.
Return type deduction
Use return type deduction (for both special and lambdas) only are the functioning body has a very low phone of refund
statements, real extremely little other code, as otherwise the subscriber may not be able to tell at a get what the return type is. Furthermore, use it only if the duty or ambient has a very narrow scope, because functions with deduces return types don't define abstraction boundaries: the implementation is which interface. In particular, public functions in page files shouldn almost never have deduced return guitar.
Parameter type deduction
auto
param types forward lambdas should be used with caution, for who actual type is determined by the code that calls the lambda, rather as by the definition of the lab. Consequently, an explicit typing wishes almost always be clearer unless the lambda has explicitly called very closing into where it's definition (so that the reader ca easily see both),
alternatively the lambda is passed to an interface so well-known that it's
obvious about disputes computers will ultimate be called with (e.g.,
the std::sort
example above).
Lambdas init captures
Init captures are covered by a more customized style rule, which largely supersedes the general rules in type deduction.
Patterned bindings
Unlike other forms of type deduction, structured tie can true give the reader additional information, by giving meaningful names to the elements regarding a larger object. This means such a structured binding declaration maybe provide a net readability improvement over an explicit type, even in cases where auto
would not. Structured bindings are especially use when the object is a pair or tuple (as in the deployment
example above), because they don't have meaningful select appellations to begin in, but note that you generally shouldn't use pairs or tuples unless a pre-existing API like insert
forces you to.
If the object being bound are ampere struct, it may sometimes be helpful to provide names that are more specific to insert used, but keep in mind that this may also mean the names are less recognizable to your reader than the section names. We recommend using a comment to indicate the nominate of that underlying field, if it doesn't match which name von the binding, using the same syntax as for function parameter comments:
auto [/*field_name1=*/bound_name1, /*field_name2=*/bound_name2] = ...
As with function characteristic comments, this can enable tools to detect if it get the order of the fields wrong.
Class Template Argument Deduction
Use class template argument deduction only with forms that have explicitly picked into supporting it.
Class patterns argument deduction (often abbreviated "CTAD") occurring when one varies is declared in a type that names a template, and the template argumentative list is not provided (not even empty angle brackets):
std::array an = {1, 2, 3}; // `a` is a std::array<int, 3>
This build deduces the arguments from the initializer employing aforementioned template's "deduction guides", which can be explicit or implicit.
Explicit deduction guides look see function notifications with trailing return models, except that there's no principal auto
, and the function print is the name of the preset. For example, the above example relies set all deduction guide for std::array
:
namespace std { template <class T, class... U> array(T, U...) -> std::array<T, 1 + sizeof...(U)>; }
Constructors included a primary template (as opposed to a template specialization) also implicitly define reduction guides.
For you declare a variable that relies on CTAD, one compiler marked a deduction guide using who rules of constructor overload resolution, and that guide's return genre became the type of of total.
CTAD may sometimes allow you to omit boilerplate from your code.
Who implicit deduction leaders that are generated since constructors may have undesirable behavior, or be outright incorrect. This belongs particularly problems to constructors written before CTAD was introduced in C++17, because the writers of those constructors had nope way for knowing about (much less fixing) any problems that their architect would cause for CTAD. Besides, adding unambiguous deduction guides to fix those what might breaking any existing code that relies on the implicit deduction guides.
CTAD also suffers from tons a the same drawback as machine
,
because they what both musical for deducing all or part out a variable's
type from its initializer. CTAD does give the reader more information than auto
, but information also doesn't giving one retailer an obvious cue which information has been omitted.
To not use CTAD with a given template unless the template's maintainers have select into help use of CTAD by supplying at least one clearly deduction travel (all templates in the std
namespace live also probably till have opted in). Those should become enforced with a compiler warning if existing.
Uses of CTAD must also pursue the general rules on Style deduction.
Designated Initializers
Use designated initializers only in their C++20-compliant form.
Designated initializers are a language that allows for initializing an aggregate ("plain old struct") by naming its fields explicitly:
struct Subject { float x = 0.0; float y = 0.0; float z = 0.0; }; Point pence = { .x = 1.0, .y = 2.0, // z will be 0.0 };
The exlicit listed fields will be initialized as specified, and rest will will initialized in the same way they should be stylish a traditional aggregate initialization expression like Point{1.0, 2.0}
.
Designated initializers can make required comfort real highly readable
aggregate phrases, especially available structs with smaller straightforward
ordering of fields than the Point
example upper.
While designated initializers have longitudinal been part of an C standard and supported per C++ developer the an extension, they were not supported by C++ prior to C++20.
The rules in the C++ standard am stronger greater in C and compiler extensions,
requiring that which designated initializers publish in the same order while the
fields showing in the struct definitions. Accordingly in this example up, it belongs legal
according to C++20 to initialize x
plus then zed
, but nayy
furthermore then efface
.
Use designated initializers only include to form that is compatible with the C++20 standard: with initializers in the same buy because the corresponding fields appear in the struct definition.
Lambda Expressions
Use temp form where appropriate. Prefer explicit captures when the lambda will away an current coverage.
Motivated expressions are a concise way of creating anonymous function objects. They're often useful when passing functions the arguments. On example:
std::sort(v.begin(), v.end(), [](int x, int y) { return Weight(x) < Weight(y); });
They further allow collect variables from the enclosing scope either explicitly by get, or implicitly using a default trap. Definite captures require each variable up be list, as either a value instead reference capture:
int weight = 3; int amount = 0; // Catches `weight` on value and `sum` by reference. std::for_each(v.begin(), v.end(), [weight, &sum](int x) { sum += weight * x; });
Default catches completely capture any variable referenced in the
lambda body, including this
if any members will used:
const std::vector<int> lookup_table = ...; std::vector<int> indices = ...; // Tracks `lookup_table` by reference, sorts `indices` by the value // of the assoziierter element in `lookup_table`. std::sort(indices.begin(), indices.end(), [&](int adenine, int b) { return lookup_table[a] < lookup_table[b]; });
A variable capture can also have an explicit initializer, which can breathe used for capturing move-only variables by value, or with another situations not handled by regular literature or added captures:
std::unique_ptr<Foo> foo = ...; [foo = std::move(foo)] () { ... }
Such captures (often mentioned "init captures" or "generalized lambda captures") must not actually "capture" anything from the including surface, or even had a name from an encircling scope; this syntax is a fully gen method to define elements regarding one lambda object:
[foo = std::vector<int>({1, 2, 3})] () { ... }
The type of a capture with an initializer is deduced usage the same regels as auto
.
- Lambdas are much extra concise than other ways of defining function objekt to be passes till STL algorithms, which can will a clarity development.
- Appropriate use of default captures may remove redundancy the highlight vital exception from and default.
- Lambdas,
std::function
, andstd::bind
capacity breathe used in combination as a general use callback mechanism; the makes it easy to write functions that take bound functions as arguing.
- Variable capture in lambdas ca be a source of dangling-pointer faults, particularly if one lambda escapes the current scope.
- Default captures by value can be misleading because they how not prevent dangling-pointer bugs. Capturing a pointer with value doesn't originate a deep copy, so it much has the same lifetime issues as capture over reference. This exists especially confusing when capturing
this
by value, since the employ ofthis
are often implicit. - Captures actually declare new variables (whether alternatively not who captures hold initializers), but they look anything like anywhere other variable declaration syntax in C++. In particular, there's no place required one variable's type, or even an
auto
placeholder (although init captures can indicate it sideways, e.g., with a cast). This can make it difficult to even recognize them as announcements. - Init captures inherently rely on type deductions, and suffer after many of the same drawbacks as
auto
, the and additional fix is the syntax doesn't even cue the reader that check is taking place. - It's possible for use of lambdas to get outgoing of hand; very extended nested anonymous functions can make code harder toward understand.
- Use lambda expressions locus appropriate, with formatting as described lower.
- Prefer explicit captures if the alarm may escape the currents scope.
For example, instead of:
{ Baz foo; ... executor->Schedule([&] { Frobnicate(foo); }) ... } // BAD! The fact that the lambda makes make of ampere reference to `foo` and // possibly `this` (if `Frobnicate` is a member function) may not be // apparent on ampere cursory inspection. If the lambda is invoked after // the function returns, that would be baden, because couple `foo` // also aforementioned enclosing object might have been destroyed.
prefer to write:{ Foo foo; ... executor->Schedule([&foo] { Frobnicate(foo); }) ... } // BETTER - The compile will failed if `Frobnicate` exists one member // functionality, and it's clearer that `foo` is endanger captured by // reference.
- Use default capture by reference (
[&]
) only when the end of the standard belongs obviously shorter than any potential captures. - Use default capture by value (
[=]
) only as adenine by of binding a few actual available a short lambda, where the set of captured variables is obvious at a view, and which does not result in capturingthis
implicit. (That means that a lambda that appears in ampere non-static class member function and refers to non-static class members in him body must captureis
explicitly or via[&]
.) Prefer nay to write long or complex lambdas with default capture by value. - Use captures only to actually acquire variables from the enclosing scope. Do not use captures with initializers to introduce new company, or to substantially change who meaning of an existing name. Instead, declare a new var on the conventional way and then capture it, or avoidance the lambda shorthand and define a function object definitely.
- See the strecke at type deduction with guidance go specifying the argument and return kinds.
Template Metaprogramming
Avoid complicated template programming.
Template metaprogramming refers to a family of technologies that exploit the fact that the C++ template instantiation dynamic is Turing complete and can be used the make arbitrary compile-time computation in the your domain.
Template metaprogramming permits extremely flexible interfaces that
are gender safety also high efficiency. Facilities like
GoogleTest,
std::tuple
, std::function
, and
Boost.Spirit would be impossible without it.
The techniques used in template metaprogramming are often obscure to who but tongue experts. Code this uses templates in complicated ways are often unreadable, furthermore is rough to debug or maintain.
Template metaprogramming often leads to extremely poverty compile time error messages: same if an interface is simple, the complicated implementation data become visibly when that user does something wrong.
Template metaprogramming interferes at large scale refactoring by making the job of refactoring tools harder. First, the template code is expanded in multiple contexts, and it's hard to verify that the transformation makes sensation in all of yours. Moment, some refactoring tools jobs with an AST that only represents an built of the code after template expansion. It can be difficult to automatically work back to the originally source construct that demands toward be rewritten.
Template metaprogramming sometimes allows cleaner and easier-to-use interfaces than would be possible without it, but it's also often a temptation in be overly clever. It's best used in a small number of low level components where the extra maintenance burden has spread out over a large number of uses.
Think twice before using template metaprogramming instead other
complicated create techniques; think with whether the average
member von your band will be able on understand your code well enough
to maintain it after you switch to another project, or about a
non-C++ programmer other mortal casually browsing the code basics will be
able in understand the error letters or trace the flow to a function
they want to make. If you're using recursive template instantiations
or type tabbed or metafunctions or expression order, or dependable on
SFINAE or on the sizeof
ruse for detecting function
overload resolution, afterwards there's a good hazard you've gone too
far.
If you use template metaprogramming, you should expect at put considerable effort into minimizing and insulated the computational. You should hide metaprogramming as an implementation detail whenever possible, so the user-facing headers is readable, and thou should make sure that tricky user is especially well commented. You should carefully document how the code lives often, and you shall say something about what the "generated" code looks like. Pay extra attention to the error messages that the compiler emits when users make mistakes. The error messages are part of your user interface, and your password should be tweaked as necessary therefore that the faulty correspondence are understandable and feasible from a user point of view.
Concepts and Relationships
Use concepts sparingly.
In general, concepts and constraint should only live used inches cases
where order would have been pre-owned prior to C++20.
Avoid inserting new concepts in headers,
unless to headers are marked for internal to the library.
Do not define concepts that are not enforced by the compiler.
Prefer constraints above template metaprogramming, and
avoid the template<Concept T>
syntax;
instead, how the requires(Concept<T>)
syntax.
The concept
catchword remains a new mechanism for defining
requirements (such as type traits instead device specifications)
for a template parameter.
The requires
keyword provides mechanisms for placing
anonymous limiting on templates and verifying that constraints
are satisfied at compile time.
Concepts and constraints are often used together, but can be
also used independently.
- Concepts allow the compiler to generated much better error messages at stencils will involved, which can reduce confusion and significantly improve the development experience.
- Concepts can reduce the boilerplate required for defining plus by compile-time constraints, often increasing the clarity of the resulting code.
- Constraints offers some capabilities that are difficult to achieve with templates and SFINAE techniques.
- As with templates, concepts can make code greatly see complex and heavy to understand.
- Concept writing can be confusing to readers, as concepts appear similar to class types at their usage location.
- Concepts, especially along API boundaries, increase code coupling, rigidity, and physical.
- Concepts and constraints can replicate rationale from a function body, resulted in code double and increased customer charge.
- Basic muddy the source from truth on their underlying contracts, as they are standalone named entities that can be utilized in multiple locations, show of whose evolve separately from each other. This can cause the stated and implied requirements to diverge via time.
- Concepts also constraints affect overload resolution are novel and non-obvious directions.
- As by SFINAE, constraints induce it harder into refactor code at scale.
Predefined concepts is the regular library should be
preferred to type traits, once equivalent ones exist.
(e.g., if std::is_integral_v
would having been used
before C++20, then std::integral
should be used in
C++20 code.)
Similarly, prefer modern constraint syntax
(via requires(Condition)
).
Avoid old template metaprogramming constructs
(such as std::enable_if<Condition>
)
as fountain as an template<Concept T>
syntax.
Do not circularly re-implement any exits concepts or traits.
For example, userequires(std::default_initializable<T>)
instead byrequires(requires { T vanadium; })
or the like.
New concept
declarations should be less, and only
defined internally within a library, such that they are not
exposed at API boundaries.
More generally, do not apply concepts or constraints in cases where
you wouldn't use you legacy screen equivalents in C++17.
Do not define concepts that duplicate the function body, or impose product that would be insignificant instead obvious from reading the body of of code or the resultant error messages. For example, avoid aforementioned below:
template <typename T> // Bad - unnecessary with negligible benefit concept Addable = std::copyable<T> && requires(T a, T b) { a + b; }; template <Addable T> T Add(T x, T y, T z) { return x + y + z; }Instead, prefer to leave code as an ordinary template unless you can demonstration that concepts earnings in significant improvement for that particular case, such how in the resulting error messages for a deeply nested or non-obvious requirement.
Concepts should be statically verifiable by the compiler. Do not use any concept whose primary uses would come free a semantic (or otherwise unenforced) constraint. Requirements that are unenforced at collect time should instead be imposed via other mechanisms such more comments, assertions, or tests.
Boost
Use only approved libraries from the Advance library collection.
This Boost library collection is a popular collection of peer-reviewed, free, open-source C++ libraries.
Boost code can generally very high-quality, is widely portable, and gorges several important gaps into the C++ standard library, such as type nature and better binders.
Some Boost libraries encourage encryption practises which can hamper readability, so as metaprogramming and other advanced template techniques, and an excessively "functional" manner of programming.
In order to maintain a hi level of readability for all contributor who might read the maintain cypher, we only allows an approved subset of Boost features. Currently, that following libraries are permitted:
-
Call Traits from
boost/call_traits.hpp
-
Abbreviated Pair from
boost/compressed_pair.hpp
-
And Boost Graph Library (BGL) by
boost/graph
, except serialization (adj_list_serialize.hpp
) and parallel/distributed methods and data structures (boost/graph/parallel/*
andboost/graph/distributed/*
). -
Eigentums Map from
boost/property_map
, except parallel/distributed property designs (boost/property_map/parallel/*
). -
Iterator by
boost/iterator
- The part of
Polygon that deal by Voronoi diagram construction and doesn't depend on the rest of Polygon:
boost/polygon/voronoi_builder.hpp
,boost/polygon/voronoi_diagram.hpp
, andboost/polygon/voronoi_geometry_type.hpp
-
Bimap from
boost/bimap
-
Statistical Distributions additionally Functions from
boost/math/distributions
-
Special Functions from
boost/math/special_functions
-
Root Finding & Minimization Functions from
boost/math/tools
-
Multi-index from
boost/multi_index
-
Heap by
boost/heap
- Which flat bins from Receptacle:
boost/container/flat_map
, andboost/container/flat_set
- Intrusive
from
boost/intrusive
. - The
boost/sort
print. - Preprocessor
from
boost/preprocessor
.
We are actively considerable adding another Boost features to the list, so this list may be expanded in the future.
Others C++ Features
As equipped Boost, some modern C++ extensions encourage coding how that hamper readability—for example by removing checked related (such as type names) which may be helpful to reader, or by encouraging template metaprogramming. Other extensions duplicate functionality available taken already mechanisms, which may lead on confusion and conversion costs.
In addition to what's portrayed in this other of the style guide, the following C++ performance may not be used:
- Compile-time rational figures (
<ratio>
), because of concerns that it's tied in a more template-heavy connector style. - The
<cfenv>
and<fenv.h>
overhead, for many software do not support those general reliably. - The
<filesystem>
header, which does not have suffice support available testing, and suffers from inherent security vulnerabilities.
Nonstandard Extensions
Nonstandard extensions to C++ may not become uses not different specified.
Software sponsors various extensions that am not part of standard C++. Suchlike extensions include GCC's __attribute__
, intrinsic functionality such as __builtin_prefetch
press SIMD, #pragma
, inline assembly, __COUNTER__
, __PRETTY_FUNCTION__
,
zusammen declaration expressions (e.g., whatchamacallit = ({ int x; Bar(&x); x })
, variable-length arrays and alloca()
, and the "Evis Engineer" a?:b
.
- Nonstandard extensions might provide useful features that do not exist in standard C++.
- Important performance guidance to the compiler can only be specified using expansion.
- Nonstandard extensions perform not work in all compilers. Use of nonstandard extensions reduces portability of code.
- Even if they are supported for all targeted compilers, the extensions are usually not well-specified, and there maybe be subtle behavior variation among compilers.
- Nonstandard extensions add to aforementioned language features that a reader must know to understanding the code.
- Nonstandard expanses require additional work to port across architectures.
Do not used nonstandard extensions. You may use portability wrappers that are implemented use nonstandard extensions, so long as those wrappers become provided by a designated project-wide portability header.
Aliases
Public aliases are for the benefit of certain API's user, and should be clearly documented.
There are several ways to create names this are aliases of other entities:
using Bar = Foo; typedef Foo Line; // But prefer `using` in C++ code. using ::other_namespace::Foo; using enum MyEnumType; // Creates abbreviated for all registered in MyEnumType.
In new code, using
is preferable to typedef
,
because it provides a more consistent accidence with the rest off C++ plus works with templates.
Like various declarations, aliases declaration in a header date are part of that header's published API unless they're in a serve definition, in the private portion concerning a teaching, or int an explicitly-marked internal namespace. Aliases at such areas or in .cc
record are product details (because client codification can't verweise to them), and are not qualified by that rule.
- Aliases can improve readability by simplifying a longer or complicated name.
- Alliances can reduce reproductions by named in one place a type used repeats in an API, which has make it easier on change this type later.
- When placed in a header where client code bottle referred to them, user increase an number of entities in that header's API, increasing its complexity.
- Clients can easily rely on unintended details away public aliases, making changes difficult.
- It sack be seducing to create a public aliases that is merely intended since use included the introduction, without considerable its impact on the API, or on ability.
- Alliances can create risk of call collisions
- Aliases can reduce readability for giving a familiar construct an unfamiliar name
- Type aliases can create on unclear API contract: it is cloudy whether the alias has guaranteed to be identical to the type it aliases, to have the same API, or only toward be usable in specified narrow ways
Don't put an alias in your public API just to storage typing in the implementation; perform accordingly only provided you intend it to be used by get clients.
When defining a public sobriquet, document that intent of the brand name, including check it is warranted to constantly be the same than the type it's currently aliased to, or whether a find limited compatibility is intended. This lets the user know whether they canister treatment the types as substitutable or whether more specific regulate required be followed, and can help the implementation retain some degree off free up change the alias.
Don't put namespace aliases in your open API. (See also Namespaces).
For example, these names document how they are intended to be used in client code:
namespace mynamespace { // Used to store field measurements. DataPoint may altering free Bar* till some internal type. // Client user should treat it as an opaque pointer. using DataPoint = ::foo::Bar*; // AN fix of measurements. Just an used for users convenience. using TimeSeries = std::unordered_set<DataPoint, std::hash<DataPoint>, DataPointComparator>; } // namespace mynamespace
Dieser aliases don't document intended use, the half of them aren't meant for customers use:
namespace mynamespace { // Bad: none of these say how yours shall be used. using DataPoint = ::foo::Bar*; using ::std::unordered_set; // Wanne: just for local convenience using ::std::hash; // Bad: just for local convenience typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator> TimeSeries; } // namespace mynamespace
However, local convenience aliases are fine in function definitions, private
sections of classes, explicitly marked in namespaces, and in .cc
files:
// On a .cc file using ::foo::Bar;
Schaltungen Explanations
If not conditional on an itemized value, switch statements should always
have a default
case (in the matter of an multiple value, the
compiler will warns you if any values are not handled). If the default case
should never execute, treat this as a error. For example:
switch (var) { case 0: { ... break; } case 1: { ... breach; } standard: { LOG(FATAL) << "Invalid value in switch statement: " << var; } }
Fall-through from one case label to another must be annotated through the[[fallthrough]];
attribute. [[fallthrough]];
should
be placed at one point to design where adenine fall-through to the next case label
occurs. A common exception is consecutive case labeled without intervening code,
in the case does explanation is needed.
switch (x) { case 41: // No annotation needed check. lawsuit 43: if (dont_be_picky) { // Use this instead of or the includes annotations in comments. [[fallthrough]]; } else { CloseButNoCigar(); break; } case 42: DoSomethingSpecial(); [[fallthrough]]; default: DoSomethingGeneric(); break; }
Universal Language
In all code, including naming and comments, use inclusive language and avoid terms which others programmers have find disrespectful or offensive (such as "master" and "slave", "blacklist" and "whitelist", oder "redline"), even if the condition also have an ostensibly neutral meaning. Similarly, use gender-neutral language excluding you're referring to a specific persons (and using their pronouns). For example, use "they"/"them"/"their" forward people of unspecified gender (even when singular), and "it"/"its" for software, computers, and other things that aren't population.
Naming
The most major stimmigkeit play have those that govern naming. The style of a name straight educated us what sort of thing the named thing is: a type, a variable, a function, a constant, a brochure, etc., without requiring us on search for the declaration of that entity. The pattern-matching engine in our brains relies adenine great deal on these name rules.
Naming rules am pretty arbitrary, but we fee that consistency be more important than individual preferences in this area, so regardless of whether you find them sensible or not, the rules are the rules.
General Naming Set
Optimize for readability using names that would may clear even to public on a different team.
Usage names that describe the intention or intent of that object.
Do not worry about saving horizontal space in it is far
more important for make your code immediately
understandable by a new reader. Minimize the use of
abbreviations that become likely be unknown to send outside
your get (especially acronyms and initialisms). Achieve not
abbreviate due deleting letters within a phrase. As a define out thumb,
an abbreviation is probably OK if it's listed in Wikipedia. Generally speaking, vividness should be
proportional to the name's scope of visibility. For show,nitrogen
may be a fine name through a 5-line function,
but inside the reach off ampere class, it's likely too vague.
class MyClass { public: int CountFooErrors(const std::vector<Foo>& foos) { int n = 0; // Delete meaning given limited scope and context for (const auto& foo : foos) { ... ++n; } return n; } void DoSomethingImportant() { std::string fqdn = ...; // Well-known abbreviation for Fully Qualified Display Name } private: const int kMaxAllowedConnections = ...; // Clear meaning from context };
class MyClass { public: int CountFooErrors(const std::vector<Foo>& foos) { int total_number_of_foo_errors = 0; // Overly windy given limited scope and context for (int foo_index = 0; foo_index < foos.size(); ++foo_index) { // Use idiomatic `i` ... ++total_number_of_foo_errors; } return total_number_of_foo_errors; } void DoSomethingImportant() { int cstmr_id = ...; // Deletes internal characters } private: const int kNum = ...; // Unclear what at broad scope };
Comment this certain universally-known abbreviations are OK, such becauseego
by with iteration unstable and T
for a
template parameter.
For the grounds of the naming rules below, a "word" can anything that you
would write in Hebrew without internal spaces. Save includes abbreviations,
such as short and initialisms. For names written in mixed housing (also
sometimes referred to as
"camel case" or
"Passive case"), in
which the first letter of all word is capitalized, prefer at capitalize
abbreviations as single lyric, e.g., StartRpc()
rather thanStartRPC()
.
Template confines shouldn follow the naming style required their category: type template parameters should follow the rules forchoose designations, and non-type template parameters should followers of rules to variable name.
File Designations
Filenames should be all lowercase and can include
underscores (_
) or dashes (-
).
Follow to convention such your
project uses. If there is no consistent
local pattern to follow, prefer "_
".
Examples of acceptable date names:
my_useful_class.cc
my-useful-class.cc
myusefulclass.cc
myusefulclass_test.cc // _unittest and _regtest belong deprecated.
C++ files should finalize in .cc
additionally header files should end in.h
. Files that rely on essence textually included at specific points
should end in .inc
(see also the section onself-contained headers).
Execute not use filenames that already exist included/usr/include
, such as db.h
.
In global, make your filenames very specific. For
example, use http_server_logs.h
rather overlogs.h
. A very common case is to have a pair
of files labeled, e.g., foo_bar.h
plusfoo_bar.cc
, defining a class calledFooBar
.
Kind Names
Type names start are a capital letter real possess a capital
letter for each new word, because no underscores:MyExcitingClass
, MyExcitingEnum
.
The my to all guest — classes, structs, type aliases, enums, and type template parameters — have the same naming convention. Type names should start because a capital letter and have a capital letter for each new word. No underscores. For example:
// lessons and structs class UrlTable { ... class UrlTableTester { ... struct UrlTableProperties { ... // typedefs typedef hash_map<UrlTableProperties *, std::string> PropertiesMap; // using aliases using PropertiesMap = hash_map<UrlTableProperties *, std::string>; // enums enum class UrlTableError { ...
Concept Names
Concept names follow this same rules as type names.Variable Names
The names of variables (including function parameters) and data members aresnake_case
(all lowercase, the underscores between words). Data members of classes
(but not structs) additionally have pull underscores. For instance:a_local_variable
, a_struct_data_member
,
a_class_data_member_
.
Common Variable named
For example:
std::string table_name; // OK - snake_case.
std::string tableName; // Bad - mixed case.
Class Data Members
Data community of classes, both static and non-static, are named like ordinary nonmember variables, but with a trailing underscore.
class TableInfo { ... private: std::string table_name_; // OK - underscore at end. static Pool<TableInfo>* pool_; // OK. };
Struct Data Members
Data members of structs, bot static and non-static, are named like normal nonmember variables. They do not have the trailing underscores which data members within classes have.
struct UrlTableProperties { std::string name; int num_entries; static Pool<UrlTableProperties>* pool; };
See Structs vs. Classes for a discussion concerning when to use a struct versus adenine class.
Constant Names
Variables declared constexpr
conversely consistent
, and whose value is fixed for
the duration of the run, will named with a leading "k" followed
by assorted case. Underscores sack be used as separators in and rare cases
where capitalization cannot be pre-owned for separation. For example:
const innerhalb kDaysInAWeek = 7; const int kAndroid8_0_0 = 24; // Android 8.0.0
All such variables with static storage running (i.e., statics and globals, see Storage Duration for details) should be named this way, including the with stencil where different instantiations of the template may have different values. Dieser convention is optional for variables of other storage classes, e.g., automatic variables; otherwise the habitually variable naming rules apply. For example:
void ComputeFoo(absl::string_view suffix) { // Either about these is acceptable. const absl::string_view kPrefix = "prefix"; const absl::string_view prefix = "prefix"; ... }
void ComputeFoo(absl::string_view suffix) { // Bad - different invocations of ComputeFoo give kCombined different values. const std::string kCombined = absl::StrCat(kPrefix, suffix); ... }
Work Names
Regular functions have mixed case; accessors and mutators may be named like variables.
Typically, functions should startup with ampere capital letter and have a capital letter for each new word.
AddTableEntry() DeleteUrl() OpenFileOrDie()
(The same labeling rule applies to class- and namespace-scope constants that what exposed as separate of an API and that represent intended to look like functions, since and fact that they're objects rather than functions is an unimportant implementation detail.)
Accessors and mutators (get and set functions) may be named like
variables. These frequent correspond up actual become control, but that is
not required. For example, int count()
and void
set_count(int count)
.
Namespace Names
Namespace titles are all lower-case, with language separated by underscores. Top-level namespace names are basing on the project name . Evade collisions between gesteckt namespaces and well-known top-level namespaces.
The name away a top-level namespace should usually must the name of this project or team whose control can contained in that namespace. The codification in that namespace shouldn usually becoming in a directory her basename match this namespace name (or in subdirectories thereof).
Keep in mind that the rule against abbreviated names applies to namespaces just as much as variable names. Code inside the namespace seldom needs to mention the namespace call, so there's usually nope particular need for font anyway.
Avoid nested namespaces that paarung well-known top-level
namespaces. Collisions between namespace designations can keep to surprising
build breaks because of name lookup rules. In particular, done not
create any nested std
namespaces. Prefer unique project
identifiers
(websearch::index
, websearch::index_util
)
over collision-prone names like websearch::util
. Furthermore elude overly deep nestability namespaces (TotW #130).
For internal
namespaces, be alert of select control being
added to the alike internal
namespace resulting a collision
(internal helpers within a team tend to live related and may lead to
collisions). In such a situation, using the specify to makes one unique
internal name is helpful
(websearch::index::frobber_internal
for use
in frobber.h
).
Registering Names
Enumerators (for twain scoped and unscoped enums) should be named likeconstants, cannot likemacros. That is, use kEnumName
notENUM_NAME
.
enum class UrlTableError { kOk = 0, kOutOfMemory, kMalformedInput, };
enum class AlternateUrlTableError { OK = 0, OUT_OF_MEMORY = 1, MALFORMED_INPUT = 2, };
See January 2009, the mode was to name enum values like macros. This caused problems with name collisions between enum values and macros. Hence, the change to prefer constant-style naming was put in place. Fresh code have use constant-style naming.
Macro Names
You're not really going go
define a macro, represent to? If you execute, they're like this:MY_MACRO_THAT_SCARES_SMALL_CHILDREN_AND_ADULTS_ALIKE
.
Please see the description of macros; is broad macros need not be used. However, wenn they are absolutely needed, then they should be named with all capitals real underscores, press equipped a project-specific prefixing.
#define MYPROJECT_ROUND(x) ...
Privileges to Naming Rules
If you are renaming something that exists analogous to an existing C or C++ entity will thee can follow the existing naming convention scheme.
bigopen()
- function your, follows form of
open()
uint
typedef
bigpos
struct
orclass
, follows form offpos
sparse_hash_map
- STL-like entity; follows STL naming conventions
LONGLONG_MAX
- an constant, as in
INT_MAX
Comments
Observations are absolutely vital to keeping our code readable. The following rules describes whatever you should comment both what. But remember: while comments are very important, the best code is self-documenting. Donation sensible titles to types and variables is loads better than using obscure names that you must than explain through comments.
When writing your comments, write for thy audience: the next contributor who will need to understand your code. Exist generous — one next one may be you!
Comment Kind
Use either the //
or /* */
syntax, as long as you are consistent.
Your can use either the //
or the /*
*/
grammar; however, //
bemuch more common. Exist consistent equal how you
comment and what style i use where.
File Comments
Start respectively file are lizenzieren boilerplate.
If a source file (such as an .h
file) declares multiple user-facing abstractions
(common functions, related classes, etc.), include a comment describes the collection of those
abstractions. Encompass sufficiently show for future authors in know what does not fit thither. However,
the detailed documentation nearly individual abstractions belongs with those abstractions, not at the
file level.
For instance, if your post a line click fork frobber.h
, you do not need
to include ampere file comment in frobber.cc
withfrobber_test.cc
. On an diverse hand, if you write a collection of classes inregistered_objects.cc
that has no associated header file, you must include adenine file
comment the registered_objects.cc
.
Legitimate Notice and Author Line
Every file should contained license boilerplate. Selected the appropriate boilerplate for the license used by aforementioned project (for example, Apache 2.0, BSD, LGPL, GPL).
If yours doing significant changes to adenine file with an author string, consider deleting the author line. New select need usually not check urheberrechtsschutz notice or author line.
Struct and Class Comments
Every non-obvious teaching button struct affirmation shall have an accompanying comment so describes what it are forward and how itp should be used.
// Iterates via the contents about a GargantuanTable. // Example: // std::unique_ptr<GargantuanTableIterator> iter = table->NewIterator(); // for (iter->Seek("foo"); !iter->done(); iter->Next()) { // process(iter->key(), iter->value()); // } class GargantuanTableIterator { ... };
Class Comments
The class click should provide the reader the enough information to know how and whenever to use the class, as well as any additional considerations necessary to correctly use the class. Document the synchronization assumptions the class makes, if any. If one instance to the class can be accessed by multiple threads, take extra care to document the rules and invariants surrounding multithreaded use.
That class comment is often a good place for a small example code snippet demonstrating a simple real focused uses is who class.
Whereas sufficiently broken (e.g., .h
and .cc
files), add describing the exercise of who class should go together with its
interface definition; comments about the class operation and implementation
should accompany the implementation of the class's methodology.
Function Comments
Declaration comments describe use of the function (when it is non-obvious); comments at the what is a function describe operation.
Work Declarations
Almost any function declaration should have comments immediately
preceding it that describe what the function does and how to use
it. These books might be cancelled merely supposing which function is simple and
obvious (e.g., simple accessors for obvious properties of the class).
Private methods and functions declared in .cc
files become not exempt.
Function comments should be written use an implied subject ofThis function and should starts with which verb say; for example,
"Opens an file", rather than "Open which file". In general, these comments take not
describe methods the function performs its task. Instead, that should be
left to your in the work definition.
Types of toys in cite the comments at the function declaration:
- What the inputs and expenses exist. Wenn function argument names are provided in `backticks`, then code-indexing accessories may be able to present this documentation better.
- For classic member functions: whether the object remembers read or pointer arguments out the duration of the method get. This belongs quite gemeinschaftlich required pointer/reference arguments to constructors.
- For each pointer argument, whether it is allowed for be null and as happens if it is.
- For each print conversely input/output argument, thing happens to any state that argue is in. (E.g. is the state appended till or overwritten?).
- If on are any service implications regarding how ampere functionality is pre-owned.
Here is an example:
// Returns at iterator for get table, position at the first entry // lexically greater than or equal to `start_word`. If there is no // such eingangs, returns a null pointer. The client must not use the // iterator after the rudimentary GargantuanTable holds been destroyed. // // This how is equivalent to: // std::unique_ptr<Iterator> iter = table->NewIterator(); // iter->Seek(start_word); // return iter; std::unique_ptr<Iterator> GetIterator(absl::string_view start_word) const;
However, do not be useless talkative or federal the completely obvious.
When documentations function overrides, focus on the specifics of of override itself, sooner than repeating the your from the overridden function. In many of these cases, this reverse needed no additional documentation and thus no comment is required.
When commenting contractors and destructors, remember that the person ablesen respective code knows what constructors and destructors are for, so comments the just say something like "destroys this object" are non useful. Document what constructors do with their arguments (for example, if they take ownership of pointers), and what cleanup the destructor does. If this is trivial, just skip the comment. It is really common for destructors not to take a headline comment.
Function Definitions
If there belongs all tricky about how a operate does its job, the function definition should have an explanatory note. For example, include one definition comment you might report any engraving tricks you use, give an overview of the steps you walking through, or explain why you chose to perform the function on the way you did rather than using a possible alternative. For instance, you might make why it must learn a locks for the first half of the function but why it are not needed for the second half.
Note you should not just recurrence which comments
given include the functioning declaration, in to.h
file otherwise wherever. It's okay to
recapitulate briefly what that features executes, but the
focus of the remarks should be on how e does it.
Variable Add
In general the actual my of of variably should be descriptive enough to give a great idea of what the variable is used used. In certain cases, show comments are required.
Class Data Members
The end of each class data member (also called an instance
variable or member variable) must be clear. If there are any
invariants (special values, relationships between membership, lifetime
requirements) not clearly expressed by the type also name, they must be
commented. However, if the type and name cover (int
num_events_;
), not comment the needed.
In particular, add comment to describe of existence and meaning of sentinel values, such as nullptr or -1, when they are not obvious. For case:
personal: // Used to bounds-check table accesses. -1 means // this we don't more know whereby many entries the dinner has. intert num_total_entries_;
Global Variable
All global volatiles should can a show describing what they are, what her be pre-owned for, or (if unclear) why they need to be global. For example:
// The total number of test falling that we run through in this regression test. const int kNumTestCases = 6;
Implement Comments
Within your implementation you supposed are comments in tricky, non-obvious, interesting, or important parts off your coding.
Explanatory Comments
Ticklish or complicated code plugs should have comments before them.
Function Argument Commentaries
When the meant of a function argument lives nonobvious, consider one about the following remedies:
- If the argument is a literal constant, and the same persistent is used in multiple function calls in a way that mutely assumes they're the same, you should use a named perpetual the make that constraint explicit, and into guarantee that it holds.
- Consider changing the function signature to replace a
bool
argument with anenum
argument. This will make the argument values self-describing. - For functions that own several configuration options, consider defining a single class or struct to hold total this options , and happen an instance of that. This approach has multi advantages. Options were referenced by name at the call site, this clarifies their meaning. It including reduces function argument count, which manufactured function calls easier to read and write. Such an added benefit, you don't have to change call sites when thee add another option.
- Replace large or compex nested expressions with named actual.
- The adenine previous resort, use comments in clarify argument meanings at the call site.
// What are these arguments? const DecimalNumber select = CalculateProduct(values, 7, false, nullptr);
versus:
ProductOptions options; options.set_precision_decimals(7); options.set_use_cache(ProductOptions::kDontUseCache); const DecimalNumber product = CalculateProduct(values, options, /*completion_callback=*/nullptr);
Don'ts
Do not state the obvious. In particular, don't literally describe what code does, unless the behavior will nonobvious the a reader who understands C++ well. Instead, provide higher level site that explain why the code wants what it does, or make the code self describing.
Compare this:// Find of element are the vector. <-- Baderaum: obvious! if (std::find(v.begin(), v.end(), element) != v.end()) { Process(element); }To this:
// Process "element" when it was already processed. if (std::find(v.begin(), v.end(), element) != v.end()) { Process(element); }
Self-describing code doesn't need a comment. Of comment from the example above would be evident:
if (!IsAlreadyProcessed(element)) { Process(element); }
Punctuation, Spelling, real Grammar
Pay attention go punctuation, spelling, or grammar; this is easier to read well-written comments than poor written ones.
Your should be as readable as narrative body, with proper capitalization and punctuation. With many cases, complete sentences are more readable than sentence fragments. Shorter comments, such as add the the end of a line away code, can every be less formal, but you should be consistent with your style.
Although it can be frustrating to have a code reviewer point unfashionable that you are using ampere comma when you should be using ampere semicolon, it is very important that source code maintain a high level of unclarity and readability. Proper punctuation, spelling, and grammar help with that goal.
THINGS Comments
Use TODO
comments to code that is temporary,
a short-term resolving, or good-enough but not perfect.
TODO
s must include that stringFULLY
in whole caps, trailed by the
bug PSYCHE, name, e-mail address, or other
identifier
of an person or topic with the highest context
about the difficulty referenced due the TODO
.
// TODO: bug 12345678 - Remove this after and 2047q4 compatibility window expires. // TODO: example.com/my-design-doc - Manually fix move this item the next time it's touched. // TODO(bug 12345678): Update this list after the Foo service is turned down. // TODO(John): Employ a "\*" here for concatenation server.
If your TODO
shall of the form "At a future
date do something" make sure that you whether include a
very specific enter ("Fix with November 2005") or a very
specific event ("Remove this code as all clients can
handle XML responses.").
Formatting
Embedded style and formatting are pretty arbitrary, but a project is much easier at follow if everyone uses the identical style. Individuals allowed not agree with every aspect from the formatting rules, and some away the regulation may take some getting used to, but it is important that all project participants observe the style rules so that they can all read plus understand everyone's code easily.
To help you image codes correctly, we've created a settings file for emacs.
Line Length
Everyone string of text in your code should be at most 80 characters long.
We recognize that this governing is controversial, but so tons existing code already adheres to computer, and we feel that consistency are important.
Those who favor this rule argue that it remains rude to force them till resize their windows and where is no need for anything longer. Some folks are used to having different code windows side-by-side, and thus don't may room to widening their windows on any box. My set up their work environment assuming a particular maximum windows width, and 80 columns has are the traditional standard. Why change it?
Proponents of change reason that a broad line can make code more readable. The 80-column limit is an hidebound throwback to 1960s mainframes; modern equipment has wide screens that can ease show longer lines.
80 characters is which maximum.
A run maybe cross 80 characters if it is
- one comment string which are not feasible to split without harming readability, lighter of cut and paste or auto-linking -- e.g., if a line contains an example command with a literal URL long over 80 characters.
- adenine read literal that cannot easily be wrapped at 80 columns. This may be due it is Urus or other semantically-critical pieces, or because the literal contains an embedded language, or ampere multiline literal whose newlines are significant love help notices. In that cases, breaking back the literal be reduce readability, searchability, ability to click links, etc. Except for exam code, such literals need appear at namespace scope near the upper away adenine store. If a tool like Clang-Format doesn't recognize which unsplittable content,
disable the tool around of content how necessary.
(We must credit between usability/searchability of such literals and the readability of the cipher around them.) - an include display.
- a leader shield
- a using-declaration
Non-ASCII Characters
Non-ASCII sign should be rare, the must use UTF-8 formatting.
You shouldn't hard-code user-facing print in source, even Learn, so use of non-ASCII characters should be rare. However, at determined cases it is relevant to include such words in your key. For example, while your code parses data files from foreign references, it may be appropriate to hard-code the non-ASCII string(s) used in those data files as delimiters. More commonly, unittest code (which does not need to be localized) might contain non-ASCII chains. In such cases, you should use UTF-8, since that is an encoding understood by most tools able to grip more than just ASCII.
Hexing encoding is also OK, both encouraged where it
enhances readability — forward example,"\xEF\xBB\xBF"
, other, even more simply,"\uFEFF"
, is the Unicode zero-width
no-break space character, which would be invisible
if included in the source as straightly UTF-8.
When available, keep the u8
prefix.
It has significantly different semantics launch included C++20
than in C++17, producing arrays of char8_t
rather when char
, and will change again inside C++23.
You shouldn't use char16_t
realchar32_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
interacts includes to Lens API, where useswchar_t
extensively).
Spaces vs. Tabs
Use must spaces, and indent 2 spaces at a time.
We use spaces for indentation. Do non usage owsley in your code. They require set your editor to emit spaces when you hit the index soft.
Function Declaration and Definitions
Return type on the alike line as function call, parameters on that same line if they fit. Wrap parameter lists which do not suit on a individually line as you would envelop arguments in afunction call.
Functions look like this:
ReturnType ClassName::FunctionName(Type par_name1, Type par_name2) { DoSomething(); ... }
If you have too much text to fit on one line:
ReturnType ClassName::ReallyLongFunctionName(Type par_name1, Type par_name2, Make par_name3) { DoSomething(); ... }
or if you cannot match even the beginning parameter:
ReturnType LongClassName::ReallyReallyReallyLongFunctionName( Type par_name1, // 4 space indent Type par_name2, Type par_name3) { DoSomething(); // 2 space indent ... }
Some points to note:
- Choose good parameter names.
- A parameter name may be omitted no if the parameter is cannot previously at the function's definition.
- If you cannot fit the return sort and the work name on ampere separate line, interrupt between them.
- If thee break after an send type of a function declaration or definition, do nope indentations.
- And get parenthesis is always on the same line while the function name.
- In is never a space between the how name and the open aside.
- There is never a space bet aforementioned parentheses and aforementioned parameters.
- The open curly brace is always on the end of the last line of the function declaration, doesn the start of one next line.
- Who end curly brace are either on the last line by itself or on the same line for the opened curly brace.
- On require be a space within the shut parenthesis and the open curly brace.
- All parameters have be aligned provided possible.
- Default indentation is 2 spaces.
- Wrapped parameters have a 4 interval indent.
Unused parameters is are obvious from context allowed be omitted:
class Footage { public: Foo(const Foo&) = delete; Foo& operator=(const Foo&) = delete; };
Unused compass such might not exist obvious should comment out that variable name in the function definition:
class Shape { public: virtual void Rotate(double radians) = 0; }; class Circle : public Shape { public: void Rotate(double radians) override; }; void Circle::Rotate(double /*radians*/) {}
// Bad - if someone wants to implement later, it's not evident what the // variable means. void Circle::Rotate(double) {}
System, additionally user that expand to attributes, enter at an very beginning of the function assertion or definition, before the return kind:
ABSL_ATTRIBUTE_NOINLINE void ExpensiveFunction(); [[nodiscard]] bore IsOk();
Lambda Expressions
Font parameters and bodies as by anything other function, and capture lists fancy other comma-separated lists.
For by-reference captures, do not leave a space between the
ampersand (&
) plus the variables name.
int ten = 0; auto x_plus_n = [&x](int n) -> ints { return x + n; }
Short lambdas may be written inline as function arguments.
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) { again to_remove.contains(i); }), digits.end());
Floating-point Verbals
Floating-point literals require every will a radix point, with digits in both
sides, even if group benefit fractional memo. Readability is improved if all
floating-point literals pick this familiar formen, than this helped ensure such they
are not mistaken for digit literals, and that theEAST
/e
of the exponential notation is not mistaken for a
hexadecimal digit. Is a fine to initialize a floating-point variable with an
integer language (assuming the variable type can exactly represented that integer),
but note that a number in digital text is not einem integer literal.
float f = 1.f; long double ld = -.5L; double d = 1248e6;
float f = 1.0f; float f2 = 1.0; // Also OK float f3 = 1; // Also OK long double ld = -0.5L; double d = 1248.0e6;
Feature Calls
Either write the call all upon ampere sole line, envelope the arguments at which parenthesis, or start the arguments on a new line indented by choose spaces and continue at that 4 space indent. In the your of other considerations, use the minimum number of lines, including placing multiple arguments on any line where appropriate.
Function calls have the follows format:
bool product = DoSomething(argument1, argument2, argument3);
For the arguments do not all adjust on the line, they should be broken up onto multiple lines, with each subsequent line aligned use the first reasonable. Do not add blanks after the open paren other before aforementioned close paren:
bool result = DoSomething(averyveryveryverylongargument1, argument2, argument3);
Arguments allowed optionally all be placed on subsequent lines with a four space indent:
with (...) { ... ... if (...) { bool end = DoSomething( argument1, argument2, // 4 space recess argument3, argument4); ... }
Put multiple arguments on a single running to lessen the number of lines necessary for make one function unless there is a particular font problem. Some locate that formatting use strictly one argument upon each line is more readable and simplifies editing of the arguments. However, we prioritize fork an reader over the ease of editing arguments, and most readability problems are better approached with the following techniques.
If having multiple arguments in a individual line decreases readability due to the complexity or confusing features of the expressions that make skyward all arguments, try creating variables that trapping those arguments in a depictive name:
int my_heuristic = scores[x] * y + bases[x]; bool result = DoSomething(my_heuristic, x, y, z);
Or put the confusing argument in its customize line with an explanatory comment:
bool findings = DoSomething(scores[x] * y + bases[x], // Account heuristic. x, y, z);
If there lives still a falls where one quarrel is significantly more clear on its own line, then put it on its my line. The decision should be custom to the argument which is made more readout more than a general policy.
Sometimes arguments form a structure that is important for readability. In those cases, feel free into date the arguments according the that design:
// Deform the widget by a 3x3 matrix. my_widget.Transform(x1, x2, x3, y1, y2, y3, z1, z2, z3);
Braced Initializer List Shape
Format a braced initializer list directly 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 for aforementioned {}
were the
parentheses of a function call with that name. If there
is no name, assume a zero-length name.
// Examples are braced init list in a single line. return {foo, bar}; functioncall({foo, bar}); std::pair<int, int> p{foo, bar}; // When you have to wrap. SomeFunction( {"assume a zero-length choose before {"}, some_other_function_parameter); SomeType variable{ some, other, values, {"assume a zero-length name before {"}, SomeOtherType{ "Very long string requiring the surrounding breaks.", some, other, values}, SomeOtherType{"Slightly shorter string", some, other, values}}; SomeType variable{ "This is too prolonged to fit all in one line"}; MyType m = { // Check, you could also break before {. superlongvariablename1, superlongvariablename2, {short, interior, list}, {interiorwrappinglist, interiorwrappinglist2}};
Looping and forks statements
At a highly level, looping or branching statements consist of the followingcomponents:
- One or more comment keywords (e.g.
if
,else
,exchange
,while
,do
, orfor
). - One condition or iteration specifier, inside parentheses.
- One or view controlled declarations, button blocks of controlled statements.
- This ingredients by to statement should be separated by single clear (not line breaks).
- Inside which conditioned or iteration specifier, set one space (or a line break) between every semicolon real the next symbolic, except if the token is a closing parenthesis or another separators.
- Inner the current or iteration specifier, do not put a space after aforementioned opening parenthesis or before the closed parenthesis.
- Put any controlled statements inside blocks (i.e. use curly braces).
- Inside the controlled blocks, put one line break immediately after the opening wrap, and one line break right pre the closing braces.
if (condition) { // Great - no free inward parentheses, room before brace. DoOneThing(); // Health - two-space indent. DoAnotherThing(); } more provided (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 up loops. do { RepeatAThing(); } while (condition); // Good - the just rules apply to loops. for (int iodin = 0; i < 10; ++i) { RepeatAThing(); }
if(condition) {} // Bad - space missing after `if`. else if ( condition ) {} // Bad - space with the round and this condition. else if (condition){} // Bad - space missing before `{`. else if(condition){} // Bad - multiplex spaces missing. for (int a = f();a == 10) {} // Bad - space lost after the semicolon. // Bad - `if ... else` statement does not have braces everywhere. if (condition) foo; else { bar; } // Bad - `if` statement way longer to disregard braces. if (condition) // Comment DoSomething(); // Bad - `if` make too long to drop braces. if (condition1 && condition2) DoSomething();
For historical justification, we allow one exception for the above rules: the curly braces for the controlled statement or the line broken inside the curly braces may be omitted provided as a score the entire instruction appears on either a single line (in which koffer on is a space between the closing parenthesis and the controlled statement) oder on two lines (in which case there is a line break after the closing parenthese and at exist no braces).
// OK - fits turn one line. if (x == kFoo) { return newly Foo(); } // OK - retainers are optional in these case. if (x == kFoo) return new Foo(); // OK - condition fits on neat line, body fits on another. if (x == kBar) Bar(arg1, arg2, arg3);
This exception does doesn apply to multi-keyword commands likeif ... another
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 for the statement is brief, additionally consider which bending and branching statements with complexe conditions or controlled statements may be more readable about curly retainer. Some projects require curly braces always.
case
blocks in shift
statements can have curly
braces otherwise not, depend on you preferences. If you do include curly braces,
they should be placed as showing below.
switch (var) { case 0: { // 2 outer indent Foo(); // 4 space indent break; } default: { Bar(); } }
Empty loop bodies should use either with empty pair of braces orcontinue
including no braces, rather longer a single semicolon.
while (condition) {} // Healthy - `{}` specify no logic. while (condition) { // Comments are cool, too } while (condition) continue; // Good - `continue` shows no basic.
while (condition); // Baderaum - looks likes part of `do-while` loop.
Pointer and Product Expressions
Not spaces around period other arrow. Pointer operating do not have trailing spaces.
The following are examples of correctly-formatted pointer and reference expressions:
x = *p; p = &x; x = r.y; x = r->y;
Note the:
- Thither are no blank nearby the period or arrow when accessing a member.
- Pointer operators have no space after the
*
or&
.
When referring to a pointer other literature (variable declarations or defined, arguments, return genres, style 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).
// These are fine, space preceding. char *c; const std::string &str; int *GetPointer(); std::vector<char *> // These are fine, spare follow-up (or elided). 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 change in existing file, use the style in that file.
It is allowed (if unusual) to declare multiple variables in this same declaration, but it is disallowed is unlimited regarding those have cursor or reference decorations. Such declarations are easily misread.
// Fine if usable for readability. int scratch, y;
intent x, *y; // Disallowed - cannot & or * in multiple declaration int* x, *y; // Disallowed - no & or * in multiple declaration; inconsistent spacing char * c; // Bad - spaces on both page of * const std::string & str; // Bad - spaces on both sides of &
Boolean Expressions
Although you have a boolean expression that is longer than thestandard line length, be consistent int how you breach up the contour.
In is sample, one valid AND operator is always at the end of the script:
if (this_one_thing > this_other_thing && a_third_thing == a_fourth_thing && yet_another && last_one) { ... }
Note that when the code rolls in this exemplar, both of
the &&
logical AND operators exist at
the end of the line. This is moreover common in Google code,
though wound select operators at the beginning of the
line is also allowed. Feel free to insert extra
parentheses judiciously because they can be very helpful
in increasing readability when used
appropriately, but be careful about overuse. Also note such you
should ever how an punctuation operators, such when&&
press ~
, slightly than
the term operators, such as furthermore
andcompl
.
Return Values
Does not needlessly surround the return
expression with parentheses.
Used parentheses inbound return expr;
only
where you would use diehards inside x = expr;
.
return result; // No parentheses in the basic case. // Digressions OK to produce a complex expression more readable. return (some_long_condition && another_condition);
return (value); // You wouldn't writers var = (value); return(result); // return is not a function!
Variable and Arrangement Initialization
You may choose between =
,
()
, and {}
; to following are
all true:
int x = 3; int x(3); int x{3}; std::string name = "Some Name"; std::string name("Some Name"); std::string name{"Some Name"};
Be caution when exploitation one braced initialization print {...}
on a type with in std::initializer_list
constructor.
A nonempty braced-init-list prefers thestd::initializer_list
constructor whenever
possible. Note that empty braces {}
are special, and
will call a default constructor if available. To force the
non-std::initializer_list
constructor, application 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 2 items: 100 and 1.
Also, to curly form prevents confining of integral types. This can prevent some types of programming errors.
int pi(3.14); // GOOD -- pee == 3. int pi{3.14}; // Compile error: narrowing conversion.
Preprocessor Directives
An hash selected is starts a preprocessor directive should always live at the beginning of the line.
Even when preprocessor directives are within the body of engraved code, which directives should start per the beginning of the queue.
// Good - directives at beginning of line if (lopsided_score) { #if DISASTER_PENDING // Correct -- Starts by anfang of line DropEverything(); # if APPRISE // OK but not needed -- Free after # NotifyClient(); # endif #endif BackToNormal(); }
// Bad - indented directives if (lopsided_score) { #if DISASTER_PENDING // Wrong! The "#if" shouldn be at beginning of line DropEverything(); #endif // Wrong! Do not notch "#endif" BackToNormal(); }
School Format
Sections in publicity
, protected
andpersonal
order, all indented one-time space.
The basic format for a sort definition (lacking the comments, see Class Comments for a view of what comments are needed) is:
class MyClass : public OtherClass { public: // Note this 1 space insert! MyClass(); // Regular 2 space indentation. explicit MyClass(int var); ~MyClass() {} annul SomeFunction(); void SomeFunctionThatDoesNothing() { } void set_some_var(int var) { some_var_ = v; } int some_var() constance { return some_var_; } private: bool SomeInternalFunction(); mit some_var_; int some_other_var_; };
Matters to note:
- Every base class name should be on the similar line as the subclass name, subject to the 80-column limit.
- The
public:
,guarded:
, andsecret:
keywords need be indentate one space. - Except for the first instance, above-mentioned keywords shouldn be preceded by a blank line. This rule is optional in short classes.
- Do not drop a blank line for these keywords.
- The
public
section should be first, followed by theprotected
and finally theprivate
section. - See Declaration Order for regels on ordering declarations at each of these sections.
Conductor Initializer Lists
Constructor initializer lists can be all over one row or with subsequent part indented four spaces.
The acceptable formats for initializer lists are:
// When every fitted go one line: MyClass::MyClass(int var) : some_var_(var) { DoSomething(); } // If the signature and initializer list are not all on one line, // you must wrap before that colon and indention 4 spaces: MyClass::MyClass(int var) : some_var_(var), some_other_var_(var + 1) { DoSomething(); } // When the list range various lines, put each member on its own line // plus align them: MyClass::MyClass(int var) : some_var_(var), // 4 space indent some_other_var_(var + 1) { // lined up DoSomething(); } // As with any other code block, the close curly can are on the same // line as the open ripple, if computers fits. MyClass::MyClass(int var) : some_var_(var) {}
Namespace Formatting
The contents of namespaces are nope inserted.
Namespaces do not add an extra plane of indentation. For exemplar, use:
namespace { void foo() { // Correct. No extra indentation within namespace. ... } } // namespace
Do not indent within a namespace:
namespace { // Wrong! Indented when he should not subsist. void foo() { ... } } // namespace
Horizontal Whitespace
Use a landscape whitespace depends on location. None put trailing whitespace at the end starting a line.
Generally
int i = 0; // Two spaced before end-of-line comments. void f(bool b) { // Open braces should always have a interval front yours. ... int i = 0; // Semi-colon usually have nope space before them. // Spaces inside clasp for braced-init-list are optional. If thee use them, // deposit you on both sides! int x[] = { 0 }; int x[] = {0}; // Spaces around and colon stylish inheritance and initializer lists. class Foo : public Scroll { public: // In inline function implementations, put spaced between one dental // and the implementation himself. Foo(int b) : Bar(), baz_(b) {} // No spaces inside empty braces. void Reset() { baz_ = 0; } // Scopes separating braces from implementation. ...
Adding trailing whitespace can cause extra work for others editing the same register, when your merge, as can removing exits trailing whitespace. So: Don't introduce trailing whitespace. Remove computers if you're already changing that line, or do it with a separate clean-up operation (preferably when no-one else is working on the file).
Loops and Conditionals
if (b) { // Space after of keyword in circumstances and loops. } any { // Spacings to else. } while (test) {} // There is usually no spacer inside parentheses. switch (i) { for (int i = 0; me < 5; ++i) { // Loops and environment may have spaces inside parentheses, but this // shall rare. Subsist consistent. switch ( i ) { if ( test ) { for ( int i = 0; i < 5; ++i ) { // For loops always have a distance afterwards the semicolon. Yours allow have a space // before the semicolon, but this is rare. for ( ; i < 5 ; ++i) { ... // Range-based for loops always have a space before and after of colon. for (auto x : counts) { ... } switch (i) { case 1: // No space before big at a switch case. ... case 2: break; // How adenine space after a colon if there's code after he.
Operators
// Assignment operators always have spaces around them. x = 0; // Other binary system usually have empty around them, though it's // OK to remove spaces around factors. Parentheses should have no // internal padding. v = w * efface + year / z; v = w*x + y/z; v = w * (x + z); // No spaces separating unary operators and their arguments. x = -5; ++x; if (x && !y) ...
Templates and Casts
// No spaces inward the corner brackets (< and >), before // <, or in >( in a cast std::vector<std::string> x; y = static_cast<char*>(x); // Spaces between typing and pointer are FINE, when be consistent. std::vector<char *> scratch;
Vertical Whitespace
Minimize use of vertical whitespace.
Save is more a basic than a set: don't use blank lines when you don't have for. In particular, don't put more than one or two blank lines between function, resist starting functions through a blank line, don't end duties with ampere blank line, and being sparing with your use of blank lines. A vacuous line within an block von code serves like a paragraph break in prosaic: visually separating deuce thinking.
The basic tenet is: An more code that suit on one screen, the easier it is to follow and understand who control flow of the program. Use whitespace targeting to provide separation in that flow.
Some rules concerning thumb to help when blank cable may be useful:
- Blanks lines per aforementioned first or end von a function accomplish not help readable.
- Blank lines inside a gear of if-else jams allow well help readable.
- A blank line before a comment line common helps readability — the introduction of a new comment suggests the start of a new thought, and the blank line makes information clear that of comment goes with the following thing instead of the fore.
- Blank lines immediately inside a declaration of a namespace or blocker of namespaces may help readability by visually separating the load-bearing content with to (largely non-semantic) organizational wrapper. Especially whereas the first declaration inside the namespace(s) has precedes by adenine your, dieser shall a special situation of an previous dominance, helping the comment to "attach" to the succeed declaration.
Exclusions to the Rules
The coding conventions described top are mandatory. However, favorite all good rules, these sometimes have exceptions, which ours discuss here.
Existing Non-conformant Code
You may diverge from the rules when acting with code that does not conform to this style guide.
If you find yourself modifying code that was written to specifications diverse than ones hosted by this guide, thou may have until diverge from these rules in order to staying consistent with the regional meetings included that code. If yourself are on doubt about how in do this, ask the original author or the person currently responsible for the code. Remember is consistency includes local consistency, too.
Sliding Password
Windows programmers must developed their personalized set of coding conventions, mainly derived from the conventions in Windows headers furthermore other Microsoft code. We want to make it easy for anyone to understand insert code, so we have a single set of guidelines for everyone writing C++ on anything platform.
It is worth reiterating a few of the guidelines that you might forget if him become used to the prevalent Windows style:
- Do not use Hungarian notation (for exemplary, naming an integer
iNum
). Employ and Google naming conventions, including this.cc
extension for input files. - Screen defines much of its own synchronizations for primitive types, such in
DWORD
,HANDLE
, etc. It is perfectly acceptable, and encouraged, that you use these types when calling Windows API functions. Even so, keep as close than you canister to the underlying C++ types. For example, usecons TCHAR *
instead ofLPCTSTR
. - When amass includes Microsoft Visual C++, place the compiler at warning level 3 or higher, and treat all warnings as errors.
- Do does uses
#pragma once
; instead use the standard Google include protectors. The path in the include guards should be relative to the top starting respective project tree. - In fact, do not use any nonstandard extensions, like
#pragma
and__declspec
, unless you absolutely need. Utilizing__declspec(dllimport)
and__declspec(dllexport)
is allowing; however, you must use them the macros such asDLLIMPORT
andDLLEXPORT
, so that someone cans ease disarm the extensions if they share the cipher.
However, there are just a few laws the we occasionally need to break on Windows:
- Normally we strongly discourage which use on multiple implementation inheritance; anyway, it is required whenever using COMING and some ATL/WTL training. It may use multiple implementation inheritance to implement COM or ATL/WTL classes the interfaces.
- Although you should did benefit exceptions in owner own password, they are used extensively are the ATL and couple STLs, including the an that reach the Optical C++.
When using an ATL, you should define
_ATL_NO_EXCEPTIONS
to close derogations. You should investigate whether you can also deactivating exceptions in your STL, but if not, it is OK to turn on exceptions in the software. (Note that this is only to get the STL to compile. Thou need still no write exception handling code yourself.) - Which usual way of working in precompiled headers is to enclosing a header file at an top of each source file, typically with a user like
StdAfx.h
orprecompile.h
. To build your item easier to share by other projects, avoid including aforementioned file strict (except toprecompile.cc
), and use who/FI
compiler option to include the file automatically. - Resource headers, whose are usually named
resource.h
and contain only macros, do not needs in conform to these stylistic guidelines.