diff --git a/cppguide.xml b/cppguide.xml index a0c2abf..9c381f5 100644 --- a/cppguide.xml +++ b/cppguide.xml @@ -4,7 +4,7 @@
-Revision 3.260 +Revision 3.274
@@ -412,6 +412,21 @@ Tashana Landray #include "base/commandlineflags.h" #include "foo/public/bar.h" ++ Exception: sometimes, system-specific code needs conditional includes. + Such code can put conditional includes after other includes. + Of course, keep your system-specific code small and localized. + Example: +
+project2::Foo
are now distinct symbols that
do not collide.
+ + Inline namespaces automatically place their names in the + enclosing scope. Consider the following snippet, for example: +
+
+ The expressions X::Y::foo()
and
+ X::foo()
are interchangeable. Inline namespaces
+ are primarily intended for ABI compatibility across versions.
+
@@ -452,6 +484,12 @@ Tashana Landray additional (hierarchical) axis of naming, in addition to the (also hierarchical) name axis provided by classes.
++ Inline namespaces, in particular, can be confusing because + names aren't actually restricted to the namespace where they + are declared. They are only useful as part of some larger + versioning policy. +
Use of unnamed namespaces in header files can easily cause violations of the C++ One Definition Rule (ODR). @@ -608,6 +646,8 @@ Tashana Landray goal of keeping public APIs as small as possible.
+constexpr
:
+ they have no dynamic initialization or destruction.
@@ -805,14 +847,30 @@ Tashana Landray itself depend on any other globals.
- Likewise, the order in which destructors are called is defined to be the
- reverse of the order in which the constructors were called. Since
- constructor order is indeterminate, so is destructor order.
- For example, at program-end time a static variable might have
- been destroyed, but code still running -- perhaps in another thread --
- tries to access it and fails. Or the destructor for a static 'string'
- variable might be run prior to the destructor for another variable that
- contains a reference to that string.
+ Likewise, global and static variables are destroyed when the
+ program terminates, regardless of whether the termination is by
+ returning from main()
or by calling
+ exit()
. The order in which destructors are called is
+ defined to be the reverse of the order in which the constructors
+ were called. Since constructor order is indeterminate, so is
+ destructor order. For example, at program-end time a static
+ variable might have been destroyed, but code still running —
+ perhaps in another thread — tries to access it and fails. Or
+ the destructor for a static string
variable might be
+ run prior to the destructor for another variable that contains a
+ reference to that string.
+
+ One way to alleviate the destructor problem is to terminate the
+ program by calling quick_exit()
instead of
+ exit()
. The difference is that quick_exit()
+ does not invoke destructors and does not invoke any handlers that were
+ registered by calling atexit()
. If you have a handler that
+ needs to run when a program terminates via
+ quick_exit()
(flushing logs, for example), you can
+ register it using at_quick_exit()
. (If you have a handler
+ that needs to run at both exit()
and
+ quick_exit()
, you need to register it in both places.)
As a result we only allow static variables to contain POD data. This
@@ -888,32 +946,65 @@ Tashana Landray
-
+ A user defined default constructor is used to initialize an object
+ if no initializer is provided. It can ensure that an object is
+ always in a valid and usable state as soon as it's constructed; it
+ can also ensure that an object is initially created in an obviously
+ "impossible" state, to aid debugging.
+
+ In-class member initialization ensures that a member variable will
+ be initialized appropriately without having to duplicate the
+ initialization code in multiple constructors. This can reduce bugs
+ where you add a new member variable, initialize it in one
+ constructor, and forget to put that initialization code in another
+ constructor.
+
+ Explicitly defining a default constructor is extra work for
+ you, the code writer.
+
+ In-class member initialization is potentially confusing if a member
+ variable is initialized as part of its declaration and also
+ initialized in a constructor, since the value in the constructor
+ will override the value in the declaration.
+
- If your class defines member variables and has no other
- constructors you must define a default constructor (one that
- takes no arguments). It should preferably initialize the
- object in such a way that its internal state is consistent
- and valid.
+ Use in-class member initialization for simple initializations,
+ especially when a member variable must be initialized the same way
+ in more than one constructor.
+
+ If your class defines member variables that aren't
+ initialized in-class, and if it has no other constructors,
+ you must define a default constructor (one that takes no
+ arguments). It should preferably initialize the object in
+ such a way that its internal state is consistent and valid.
The reason for this is that if you have no other
@@ -1068,6 +1159,90 @@ Tashana Landray
+ Delegating and inheriting constructors are two different features,
+ both introduced in C++11, for reducing code duplication in
+ constructors. Delegating constructors allow one of a class's
+ constructors to forward work to one of the class's other
+ constructors, using a special variant of the initialization list
+ syntax. For example:
+
+ Inheriting constructors allow a derived class to have its base
+ class's constructors available directly, just as with any of the
+ base class's other member functions, instead of having to redeclare
+ them. This is especially useful if the base has multiple
+ constructors. For example:
+
+ This is especially useful when
+ Delegating and inheriting constructors reduce verbosity
+ and boilerplate, which can improve readability.
+
+ Delegating constructors are familiar to Java programmers.
+
+ It's possible to approximate the behavior of delegating constructors
+ by using a helper function.
+
+ Inheriting constructors may be confusing if a derived class
+ introduces new member variables, since the base class constructor
+ doesn't know about them.
+
+ Use delegating and inheriting
+ constructors when they reduce boilerplate and improve
+ readability. Be cautious about inheriting
+ constructors when your derived class has new member variables.
+ Inheriting constructors may still be appropriate in that case
+ if you can use in-class member initialization for the derived
+ class's member variables.
+
+
+ Operator overloading can make code appear more intuitive because a
+ class will behave in the same way as built-in types (such as
+
+ For some template functions to work correctly, you may need to
+ define operators.
+
+ User-defined literals are a very concise notation for creating
+ objects of user-defined types.
+ new
a
- class object with no arguments. It is always called when
- calling new[]
(for arrays).
+ The default constructor is called when we new
a class
+ object with no arguments. It is always called when calling
+ new[]
(for arrays). In-class member initialization means
+ declaring a member variable using a construction like int count_
+ = 17;
or string name_{"abc"};
, as opposed to just
+ int count_;
or string name_;
.
Derived
's constructors
+ don't have to do anything more than calling Base
's
+ constructors.
+ struct
only for passive objects that carry data;
@@ -1274,21 +1449,32 @@ Tashana Landray
+
and
/
operate on the class as if it were a built-in
- type.
+ type. An overload of operator""
allows
+ the built-in literal syntax to be used to create objects of
+ class types.
int
). Overloaded operators are more playful
- names for functions that are less-colorfully named, such as
- Equals()
or Add()
. For some
- template functions to work correctly, you may need to define
- operators.
+ int
). Overloaded operators are more playful names for
+ functions that are less-colorfully named, such as
+ Equals()
or Add()
.
+ operator&
, it
@@ -1323,6 +1512,10 @@ Tashana Landray
unary operator&
at all costs, if there's
any possibility the class might be forward-declared.
+ Do not overload operator""
, i.e.
+ do not introduce user-defined literals.
+
However, there may be rare cases where you need to overload
an operator to interoperate with templates or "standard" C++
@@ -1462,55 +1655,115 @@ Tashana Landray
-
+ "Ownership" is a bookkeeping technique for managing dynamically
+ allocated memory (and other resources). The owner of a dynamically
+ allocated object is an object or function that is responsible for
+ ensuring that it is deleted when no longer needed. Ownership can
+ sometimes be shared, in which case the last owner is typically
+ responsible for deleting it. Even when ownership is not shared,
+ it can be transferred from one piece of code to another.
+
+ "Smart" pointers are classes that act like pointers, e.g. by
+ overloading the
+ If dynamic allocation is necessary, prefer to keep ownership with
+ the code that allocated it. If other code needs access to the object,
+ consider passing it a copy, or passing a pointer or reference
+ without transferring ownership. Prefer to use
+ unique_ptr
- is great, and scoped_ptr
is fine if you need to support
- older versions of C++. You should only use shared_ptr
- with a non-const referent when it is truly necessary to share ownership
- of an object (e.g. inside an STL container). You should never use
- auto_ptr
.
+ Prefer to have single, fixed owners for dynamically allocated objects.
+ Prefer to transfer ownership with smart pointers.
*
and ->
operators.
+ Some smart pointer types can be used to automate ownership
+ bookkeeping, to ensure these responsibilities are met.
+
+ std::unique_ptr
is a smart pointer type introduced
+ in C++11, which expresses exclusive ownership of a dynamically
+ allocated object; the object is deleted when the
+ std::unique_ptr
goes out of scope. It cannot be copied,
+ but can be moved to represent ownership transfer.
+ shared_ptr
is a smart pointer type which expresses
+ shared ownership of a dynamically allocated object.
+ shared_ptr
s can be copied; ownership of the object is
+ shared among all copies, and the object is deleted when the last
+ shared_ptr
is destroyed.
+
+
auto_ptr
) can be nonobvious and confusing. The
- exception-safety benefits of smart pointers are not decisive, since
- we do not allow exceptions.
+
+
std::unique_ptr
expresses ownership transfer
+ using C++11's move semantics, which are
+ generally forbidden in Google
+ code, and may confuse some programmers.
-
+ unique_ptr
scoped_ptr
unique_ptr
unless C++03 compatibility is
- required.auto_ptr
unique_ptr
instead, if possible.std::unique_ptr
to make ownership transfer explicit.
+ For example:
+ shared_ptr
shared_ptr<const
- T>
). Reference-counted pointers with non-const referents
- can occasionally be the best design, but try to rewrite with single
- owners where possible.
-
+ Do not design your code to use shared ownership without a very good
+ reason. One such reason is to avoid expensive copy operations,
+ but you should only do this if the performance benefits are
+ significant, and the underlying object is immutable (i.e.
+ shared_ptr<const Foo>
). If you do use shared
+ ownership, prefer to use shared_ptr
.
+
+
+ Do not use scoped_ptr
in new code unless you need to be
+ compatible with older versions of C++. Never use
+ linked_ptr
or std::auto_ptr
. In all three
+ cases, use std::unique_ptr
instead.
+
std::forward
,
+ std::move_iterator
, or std::move_if_noexcept
.
+ Use the single-argument form of std::move
only with
+ non-copyable arguments.
+ void f(string&& s);
declares a
+ function whose argument is an rvalue reference to a string.
+ v1
is a vector<string>
,
+ for example, then auto v2(std::move(v1))
will probably
+ just result in some simple pointer manipulation instead of copying a
+ large amount of data. In some cases this can result in a major
+ performance improvement.
+ std::move
is necessary to make effective use of some
+ standard-library types, such as std::unique_ptr
.
+
+ Do not use rvalue references, and do not use the
+ std::forward
or std::move_if_noexcept
+ utility functions (which are essentially just casts to rvalue
+ reference types), or std::move_iterator
. Use
+ single-argument std::move
only with objects that are
+ not copyable (e.g. std::unique_ptr
), or in templated
+ code with objects that might not be copyable.
+
+ This prohibition also applies to the exception-related
+ features added in C++11, such as noexcept
,
+ std::exception_ptr
, and
+ std::nested_exception
.
+
There is an exception to this
rule (no pun intended) for Windows code.
@@ -2179,6 +2507,8 @@ Tashana Landray
+
- For pointers (address values), there is a choice between const
whenever it makes sense.
+ With C++11,
+ constexpr
is a better choice for some uses of const.
constexpr
+ to define true constants or to ensure constant initialization.
+ constexpr
+ to indicate the variables are true constants,
+ i.e. fixed at compilation/link time.
+ Some functions and constructors can be declared constexpr
+ which enables them to be used
+ in defining a constexpr
variable.
+ constexpr
enables
+ definition of constants with floating-point expressions
+ rather than just literals;
+ definition of constants of user-defined types; and
+ definition of constants with function calls.
+ constexpr
definitions enable a more robust
+ specification of the constant parts of an interface.
+ Use constexpr
to specify true constants
+ and the functions that support their definitions.
+ Avoid complexifying function definitions to enable
+ their use with constexpr
.
+ Do not use constexpr
to force inlining.
+ %u
- %"PRIuS"
,
%"PRIxS"
C99 specifies
+ %zu
+ C99 specifies
%zu
@@ -2587,8 +2962,8 @@ Tashana Landray
ptrdiff_t
%d
- %"PRIdS"
C99 specifies
+ %zd
+ C99 specifies
%td
0
- and NULL
(and, for C++11, nullptr
).
+ For pointers (address values), there is a choice between 0
,
+ NULL
, and nullptr
.
For projects that allow C++11 features, use nullptr
.
For C++03 projects, we prefer NULL
because it looks like a
pointer. In fact, some C++ compilers provide special definitions of
@@ -2817,6 +3192,58 @@ Tashana Landray
A @const
annotation on a method additionally
- implies that the method should not be overridden in subclasses.
+ implies that the method cannot not be overridden in subclasses.
A @const
annotation on a constructor implies the
+ class cannot be subclassed (akin to final
in Java).
+
The open source compiler will allow the symbol it to be +
The open source compiler will allow the symbol to be
overwritten because the constant is
not marked as @const
.
In this case, the pointer can never be overwritten, but
value is highly mutable and not constant (and thus in
camelCase
, not ALL_CAPS
).
x[ffVersion][isIE]()
.die
is called unless
- resultOfOperation()
is NaN
and
- THINGS_TO_EAT
gets assigned the result of
- die()
.x[ffVersion, ieVersion][isIE]()
.
+ die
is always called since the array minus 1 is
+ NaN
which is never equal to anything (not even if
+ resultOfOperation()
returns NaN
) and
+ THINGS_TO_EAT
gets assigned the result of
+ die()
.