Prefer passing objects by const& instead of by value. [18, 71]
Prefer precomputing values that won't change, instead of recreating
objects unnecessarily. [18]
For consistency, always implement post-increment in terms of
pre-increment, otherwise your users get surprising (and often unpleasant)
results. [19, 74]
Prefer pre-increment. Only use post-increment if you're going to use
the original value. [19]
Watch out for hidden temporaries created by implicit conversions.
One good way to avoid this is to make constructors explicit when
possible and avoid writing conversion operators. [19, 71]
Be aware of object lifetimes. Never, ever, ever return pointers or
references to local automatic objects; they are completely unuseful
because the calling code can't follow them, and (what's worse) the
calling code might. [21]
Reuse code - especially standard library code - instead of
handcrafting your own. It's faster, easier, and safer. [23, 70]
If a function isn't going to handle (or translate or deliberately
absorb) an exception, it should allow the exception to propagate up to
a caller who can handle it. [28]
Always structure your code so that resources are correctly freed and
data is in a consistent state even in the presence of exceptions. [28]
Prefer cohesion. Always endeavor to give each piece of code - each
module, each class, each function - a single well-defined responsibility.
[36, 44, 67, 85]
Always use the "initialization is resource acquisition" idiom to
isolate resource ownership and management. [46, 58]
Design with reuse in mind. [54]
Always be exception-aware. Know what code might emit exceptions. [63]
Prefer writing "a op= b" instead of "a = a op b". It's clearer, and
it's often more efficient. [71]
If you supply a standalone version of an operator (for example
operator+), always supply an assignment version of the same
operator (operator+=) and prefer implementing the former in terms
of the latter. Also, always preserve the natural relationship between
op and op=. [72]
Prefer the following guidelines for making an operator a member
versus a non-member: [72]
=()[] and -> must be members
>> and << are always non-members (and
friends if needed)
if the function needs to be virtual, make it a member
if it needs type conversion on its left-most operand, make it
a non-member
if it can be implemented using the class' public interface alone,
make it a non-member, non-friend
else - make it a member
Always return stream references from operator>>
and operator<<. [73]
Make base class destructors virtual (unless you are
certain that no one will ever attempt to delete a derived object
through a pointer to base). [77]
When providing a function with the same name as inherited
functions, be sure to bring the inherited functions into scope with a
using declaration if you don't want to hide them. [78]
Never change the default parameters of overriden inherited
functions. [78]
Never inherit publicly to reuse code (in the base class); inherit
publicly in order to be reused (by code that uses base objects
polymorphically). [81, 96]
When modeling "is implemented in terms of", always prefer
membership/aggregation, not inheritance. Use private inheritance
only when inheritance is absolutely necessary - that is, when you
need access to protected members or you need to override a
virtual function. Never use public inheritance for code
reuse. [82]
Avoid public virtual functions; prefer using the
Template Method pattern instead. [84]
For widely used classes, prefer to use the compiler-firewall
idiom (Pimpl idiom) to hide implementation details. Use an opaque
pointer (a pointer to a declared but undefined class) declared as
struct XxxImpl* pimpl; to store private members (including
both state variables and member functions) - for example,
class Map { private: struct MapImpl* pimpl; };. [85, 105, 110]
Prefer aggregation (aka composition, layering, "has a",
delegation) to inheritance. When modeling "is implemented in terms
of", always prefer expressing it using aggregation, not inheritance.
[90]
Always ensure that public inheritance models both "is a" and
"works like a" according to the Liskov Substitution Principle. All
overridden member functions must require no more and promise no less.
[96]
Never #include unnecessary header files. [100]
Prefer to #include <iosfwd> when a forward declaration
of a stream will suffice. [101]
Never #include a header when a forward declaration will
suffice. [102]
Never inherit when composition is sufficient. [108]
Avoid inlining or detailed tuing until performance profiles prove
the need. [116, 191]
Use namespaces wisely. If you put a class into a namespace,
be sure to put all helper functions and operators into the same
namespace, too. If you don't, you may discover surprising effects
in your code. [140]
Understand the five major distinct memory stores, why they're different,
and how they behave: stack (automatic variables); free store
(new, delete); heap (malloc, free);
global scope (statics, global variables, file scope variables, and so
forth); const data (string literals, and so forth). [143]
Prefer using the free store (new, delete). Avoid using
the heap (malloc, free). [143]
Always provide both class-specific new (or new[]) and
class-specific delete (or delete[]) if you provide either.
[146, 150]
Always explicitly declare operator new() and operator
delete() as static functions. They are never non-static member
functions. [147, 148]
Never treat arrays polymorphically. [147]
Prefer using vector<> or deque<> instead of
arrays. [148]
Never write a copy assignment operator that relies on a check for
self-assignment in order to work properly; an exception-safe copy
assignment operator is automatically safe for self-assignment. [160]
It's all right to use a self-assignment check as an optimization to
avoid needless work. [160]
Always endeavor to write exception-safe code. Always structure code
so that resources are correctly freed and data is in a consistent state
even in the presence of exceptions. [164, 168, 197]
Avoid the "dusty corners" of a language; use the simplest techniques
that are effective. [165, 168, 191]
Avoid unnecessarily terse or clever code, even if it's perfectly
clear to you when you first write it. [168]
Prefer providing a nonthrowing Swap() and implement copy
assignment in terms of copy construction as follows: [170]
// GOOD
T& T::operator=( const T& other ) {
T temp( other );
Swap( temp );
return *this;
}
Never use the trick of implementing copy assignment in terms of
copy construction by using an explicit destructor followed by placement
new, even though this trick crops up every three months on the
newsgroups. Never write - [171]
// BAD
T& T::operator=( const T& other ) {
if (this != &other) {
this->~T(); // evil
new (this) T( other ); // evil
}
return *this;
}
Prefer using the form "T t(u);" instead of "T t = u;"
where possible. The former usually works wherever the latter works, and
has other advantages - for example, it can take multiple parameters. [174]
Avoid declaring const pass-by-value function parameters. [176]
When using return-by-value for non-builtin return types, prefer
returning a const value. [177]
Prefer new-style casts. Only dynamic_cast() is not equivalent
to a C-style cast. All other new-style casts have old-style equivalents.
[183]
Avoid casting away const. Use mutable instead. [185]
Avoid downcasts. [186]
Prefer passing objects by reference instead of by value, using
const wherever possible. [191]
Avoid using global or static objects. If you must use a global or
static object, always be very careful about the order-of-initialization
rules. [194]
Always list base classes in a constructor's initialization list in
the same order in which they appear in the class definition. [196]
Always list the data members in a constructor's initialization list
in the same order in which they appear in the class definition. [196]
Common mistakes
Never make exception safety an afterthought. Exception safety affects
a class's design. It is never "just an implementation detail." [17, 35]
"Exception-unsafe" and "poor design" go hand in hand. If a piece of
code isn't exception-safe, that's generally okay and can simply be fixed.
But if a piece of code cannot be made exception-safe because of its
underlying design, that almost always is a signal of its poor design.
Example 1: a function with two different responsibilities is difficult to
make exception-safe. Example 2: a copy assignment operator that
has to check for self-assignment cannot be exception-safe. [37]
Never use public inheritance except to model true Liskov "is a" and
"works like a". All overridden member functions must require no more and
promise no less. [81]
"T t(u);" is always initialization; it is never assignment,
and so it never calls T::operator=(). It is just a syntax
holdover from C, not an assignment operation. [174]
Never write code that depends on the order of evaluation of function
arguments. [198, 199]
Canonical exception-safety rules
Never allow an exception to escape from a destructor or from an
overloaded operator delete or operator delete[]. [29, 57, 58]
In each function, take all code that might emit an exception and do
all that work safely off to the side. Only then, when you know that the
real work has succeeded, should you modify the program state (and clean
up) using only non-throwing operations. [32, 34, 47, 58]