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_ptrs 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_ptrscoped_ptrunique_ptr unless C++03 compatibility is
- required.auto_ptrunique_ptr instead, if possible.std::unique_ptr to make ownership transfer explicit.
+ For example:
+ shared_ptrshared_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
%td0
- 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().