diff --git a/cppguide.html b/cppguide.html index d4993d1..21a21f3 100644 --- a/cppguide.html +++ b/cppguide.html @@ -579,6 +579,7 @@ below. Terminate namespaces with comments as shown in the given examples. See also the rules on Namespace Names.
+You may use a using-declaration
- anywhere in a .cc
file (including in
- the global namespace), and in functions,
- methods, classes, or within internal namespaces in
- .h
files.
Do not use using-declarations in .h
- files except in explicitly marked internal-only
- namespaces, because anything imported into a namespace
- in a .h
file becomes part of the public
+
Do not use Namespace aliases at namespace scope + in header files except in explicitly marked + internal-only namespaces, because anything imported into a namespace + in a header file becomes part of the public API exported by that file.
-// OK in .cc files. -// Must be in a function, method, internal namespace, or -// class in .h files. -using ::foo::bar; --
Namespace aliases are allowed anywhere where
- a using-declaration is allowed. In particular,
- namespace aliases should not be used at namespace scope
- in .h
files except in explicitly marked
- internal-only namespaces.
// Shorten access to some commonly used names in .cc files. namespace baz = ::foo::bar::baz;@@ -871,13 +853,14 @@ for static variables are called is only partially specified in C++ and can even change from build to build, which can cause bugs that are difficult to find. Therefore in addition to banning globals of class type, -we do not allow static POD variables to be initialized +we do not allow namespace-scope static variables to be initialized with the result of a function, unless that function (such as getenv(), or getpid()) does not itself depend on any -other globals. (This prohibition does not apply to a static -variable within function scope, since its initialization -order is well-defined and does not occur until control -passes through its declaration.) +other globals. However, a static POD variable within +function scope may be initialized with the result of a +function, since its initialization order is well-defined +and does not occur until control passes through its +declaration.
Likewise, global and static variables are destroyed when the program terminates, regardless of whether the @@ -980,9 +963,9 @@ of the constructor.
IsValid() state checking mechanism (or similar) which is easy to forget to call.static const
data
members)We do not allow default function parameters, except in -limited situations as explained below. Simulate them with -function overloading instead, if appropriate.
+Default arguments are allowed on non-virtual functions +when the default is guaranteed to always have 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 the downsides below.
Defaulted arguments are another way to achieve the +semantics of overloaded functions, so all the reasons not to overload +functions apply.
+ +The defaults for arguments in a virtual function call are +determined by the static type of the target object, and +there's no guarantee that all overrides of a given function +declare the same defaults.
+ +Default parameters are re-evaluated at each call site, +which can bloat the generated code. Readers may also expect +the default's value to be fixed at the declaration instead +of varying at each call.
+Function pointers are confusing in the presence of default arguments, since the function signature often -doesn't match the call signature. Adding a default -argument to an existing function changes its type, which -can cause problems with code taking its address. Adding -function overloads avoids these problems. In addition, -default parameters may result in bulkier code since they -are replicated at every call-site -- as opposed to -overloaded functions, where "the default" appears only in -the function definition.
+doesn't match the call signature. Adding +function overloads avoids these problems.While the cons above are not that onerous, they still -outweigh the (small) benefits of default arguments over -function overloading. So except as described below, we -require all arguments to be explicitly specified.
+Default arguments are banned on virtual functions, where
+they don't work properly, and in cases where the specified
+default might not evaluate to the same value depending on
+when it was evaluated. (For example, don't write void
+f(int n = counter++);
.)
One specific exception is when the function is a -static function (or in an unnamed namespace) in a .cc -file. In this case, the cons don't apply since the -function's use is so localized.
- -In addition, default function parameters are allowed in -constructors. Most of the cons listed above don't apply to -constructors because it's impossible to take their address.
- -Another specific exception is when default arguments -are used to simulate variable-length argument lists.
- - -// Support up to 4 params by using a default empty AlphaNum. -string StrCat(const AlphaNum &a, - const AlphaNum &b = gEmptyAlphaNum, - const AlphaNum &c = gEmptyAlphaNum, - const AlphaNum &d = gEmptyAlphaNum); -+
In some other cases, default arguments can improve the +readability of their function declarations enough to +overcome the downsides above, so they are allowed. When in +doubt, use overloads.
Use C++ casts like static_cast<>()
. Do
-not use other cast formats like int y =
-(int)x;
or int y = int(x);
.
Use C++-style casts
+like static_cast<float>(double_value)
, or brace
+initialization for conversion of arithmetic types like
+int64 y = int64{1} << 42
. Do not use
+cast formats like
+int y = (int)x
or int y = int(x)
(but the latter
+is okay when invoking a constructor of a class type).
The problem with C casts is the ambiguity of the -operation; sometimes you are doing a conversion +
The problem with C casts is the ambiguity of the operation;
+sometimes you are doing a conversion
(e.g., (int)3.5
) and sometimes you are doing
-a cast (e.g., (int)"hello"
); C++
-casts avoid this. Additionally C++ casts are more visible
-when searching for them.
(int)"hello"
). Brace
+initialization and C++ casts can often help avoid this
+ambiguity. Additionally, C++ casts are more visible when searching for
+them.
The syntax is nasty.
+The C++-style cast syntax is verbose and cumbersome.
Do not use C-style casts. Instead, use these C++-style -casts.
+Do not use C-style casts. Instead, use these C++-style casts when +explicit type conversion is necessary.
static_cast
as the equivalent of a
- C-style cast that does value conversion, or when you need to explicitly up-cast a
- pointer from a class to its superclass.static_cast
as the equivalent of a C-style cast
+ that does value conversion, when you need to
+ explicitly up-cast a pointer from a class to its superclass, or when
+ you need to explicitly cast a pointer from a superclass to a
+ subclass. In this last case, you must be sure your object is
+ actually an instance of the subclass.const_cast
to remove the
const
qualifier (see const).reinterpret_cast
to do unsafe
conversions of pointer types to and from integer and
other pointer types. Use this only if you know what you
are doing and you understand the aliasing issues.
const
.const T&
) or
+ pointer-to-const (const T*
), respectively.const
whenever
possible. Accessors should almost always be
@@ -3652,8 +3644,11 @@ current scope. For example, instead of:
executor->Schedule([&] { Frobnicate(foo); })
...
}
-// BAD! `Frobnicate` may be a member function and `foo` may be destroyed
-// by the time the lambda runs.
+// BAD! The fact that the lambda makes use of a reference to `foo` and
+// possibly `this` (if `Frobnicate` is a member function) may not be
+// apparent on a cursory inspection. If the lambda is invoked after
+// the function returns, that would be bad, because both `foo`
+// and the enclosing object could have been destroyed.
prefer to write:
{ @@ -3662,9 +3657,9 @@ prefer to write: executor->Schedule([&foo] { Frobnicate(foo); }) ... } -// GOOD - The lambda cannot accidentally capture `this` and -// the explicit by-reference capture is more obvious and therefore -// more likely to be checked for correctness. +// BETTER - The compile will fail if `Frobnicate` is a member +// function, and it's clearer that `foo` is dangerously captured by +// reference.
<fenv.h>
headers, because many
compilers do not support those features reliably.void X::Foo()
+ &
or void X::Foo() &&
, because of concerns
+ that they're an overly obscure feature.Public aliases are for the benefit of an API's user, and should be clearly documented.
+There are several ways to create names that are aliases of other entities:
+typedef Foo Bar; +using Bar = Foo; +using other_namespace::Foo; ++ +
Like other declarations, aliases declared in a header file are part of that + header's public API unless they're in a function definition, in the private portion of a class, + or in an explicitly-marked internal namespace. Aliases in such areas or in .cc files are + implementation details (because client code can't refer to them), and are not restricted by this + rule.
+Don't put an alias in your public API just to save typing in the implementation; + do so only if you intend it to be used by your clients.
+When defining a public alias, document the intent of +the new name, including whether it is guaranteed to always be the same as the type +it's currently aliased to, or whether a more limited compatibility is +intended. This lets the user know whether they can treat the types as +substitutable or whether more specific rules must be followed, and can help the +implementation retain some degree of freedom to change the alias.
+Don't put namespace aliases in your public API. (See also Namespaces). +
+ +For example, these aliases document how they are intended to be used in client code:
+namespace a { +// Used to store field measurements. DataPoint may change from Bar* to some internal type. +// Client code should treat it as an opaque pointer. +using DataPoint = foo::bar::Bar*; + +// A set of measurements. Just an alias for user convenience. +using TimeSeries = std::unordered_set<DataPoint, std::hash<DataPoint>, DataPointComparator>; +} // namespace a ++ +
These aliases don't document intended use, and half of them aren't meant for client use:
+ +namespace a { +// Bad: none of these say how they should be used. +using DataPoint = foo::bar::Bar*; +using std::unordered_set; // Bad: just for local convenience +using std::hash; // Bad: just for local convenience +typedef unordered_set<DataPoint, hash<DataPoint>, DataPointComparator> TimeSeries; +} // namespace a ++ +
However, local convenience aliases are fine in function definitions, private sections of + classes, explicitly marked internal namespaces, and in .cc files:
+ +// In a .cc file +using std::unordered_set; ++ +
The names of all types — classes, structs, typedefs, +
The names of all types — classes, structs, type aliases, enums, and type template parameters — have the same naming convention. Type names should start with a capital letter and have a capital letter for each new word. No underscores. For example:
@@ -4144,6 +4234,9 @@ struct UrlTableProperties { ... // typedefs typedef hash_map<UrlTableProperties *, string> PropertiesMap; +// using aliases +using PropertiesMap = hash_map<UrlTableProperties *, string>; + // enums enum UrlTableErrors { ... @@ -4256,6 +4349,11 @@ DeleteUrl() OpenFileOrDie() +(The same naming rule applies to class- and namespace-scope +constants that are exposed as part of an API and that are intended to look +like functions, because the fact that they're +objects rather than functions is an unimportant implementation detail.)
+Functions that are very cheap to call may instead follow the style for variable names (all lower-case, with underscores between words). The rule of thumb is that such a function should be so cheap that you @@ -4324,7 +4422,7 @@ details from user-facing declarations, one common choice is
Preferably, the individual enumerators should be named
like constants. However, it
is also acceptable to name them like
-macros. The enumeration name,
+macros. The enumeration name,
UrlTableErrors
(and
AlternateUrlTableErrors
), is a type, and
therefore mixed case.
TODO
s should include the string
TODO
in all caps, followed by the
-name, e-mail address, or other
-identifier of the person
- with the best context
+name, e-mail address, bug ID, or other
+identifier
+of the person or issue with the best context
about the problem referenced by the TODO
. The
main purpose is to have a consistent TODO
that
can be searched to find out how to get more details upon
request. A TODO
is not a commitment that the
person referenced will fix the problem. Thus when you create
-a TODO
, it is almost always your
-
-name
-that is given.
TODO
with a name, it is almost always your
+name that is given.
// TODO(kl@gmail.com): Use a "*" here for concatenation operator. // TODO(Zeke) change this to use relations. +// TODO(bug 12345): remove the "Last visitors" feature
A raw-string literal may have content that exceeds 80 characters. Except for test code, such literals -should appear near top of a file.
+should appear near the top of a file.An #include
statement with a
long path may exceed 80 columns.