1.Use Objects to manage resources
callers are responsible for deleting the object that called function return when they are done with it.
resources are acquired and immediately turned over to resource-managing objects.
resource-managing objects use their destructors to ensure that resources are released.
2. think carefully about copying behavior in resource-managing classes.
not all resources are heap-based.
1.Prohibit copying. declare the copying operations private.
2.reference-cout the underlying resource.
3. Provide access to raw resources in resource-managing classes.
In a perfect well-designed systems, you'd rely on such classes for all your interactions with resources.
auto_ptr overloads the pointer dereferencing operators and this allows implicit conversion to the underlying raw pointers.
4. Use the same form in corresponding uses of new and delete.
5. Store newed objects in smart pointers in standalone statements.
unlike the way languages like java and C# work, where function parameters are always evaluated in a particular order,
C++ compilers are granted considerable latitude in determining the order in which parameters code are generated.
Designs and Declarations.
Software Designs are approaches to getting software to do what you want it to do. typically begin as fairly general ideas.
which are turned to detailed interfaces , and eventually translated into c++ declarations.
1. Make interfaces easy to use correctly and hard to use incorrectly.
An especially feature of shared_ptr is to eliminate a potential client error, "cross-DLL problem".
2. Treat class design as type design.
3. pass parameters by reference over pass-by-value.
passing parameters by reference is much more efficient and avoid the slicing problem.
the rule doesn't apply to built-in types and STL iterators and function objects.
4. Don't try to return a reference when you must return an object.
Never return a pointer to a local stack object, a reference to a heap-allocated object or a pointer or reference
to a local static object.
5. Declare data members private.
Hiding data members behind functional interfaces can offer all kinds of implementation flexibility.
access control of read and write. verify. perform synchronization in threaded environments.
6. Prefer non-member non-friend functions to member functions.
7. Declare non-member functions when type conversions should apply to all parameters.
8. Consider support for a non-throwing swap.
Implementations
1. Postpone variable definitions as long as possible.
whenever you define a variable, you incur the cost of construction and destruction.
Prefer Copy constructor over assignment operator.
2. Minimize casting.
const_cast is typically used to cast away the constness of objects.
dynamic_cast is used to perform safe downcasting to determine whether an object is of a particular type
reinterpret_cast is intended for low-level casts that yield implementation dependent.
static_cast can be used to force implicit conversions.static_cast does not run-time check. it's unsafe.
3. Avoid returning handles to object internals. It increases encapsulation, help const functions act const and
minimize the creation of dangling handles.
4. Strive for exception-safe code.
three guarantees:
basic guarantee promise that if an exception is thrown, everything in the program remains in a valid state.
strong guarantion promise if an exception is thrown the program is unchanged. this can be implemented via copy and swap.
nothrow guarantee promise never to throw exceptions.
5. Understand the ins and outs of inlining.
inline is a request to the compiler , not a command.
Constructors and destructors are often worse candidates for inling. Looks can be deceiving.
because compilers deal with exceptions in sophisticated ways when generating equivalent code for ctor
Limit most inlining to small, frequently called functions. This facilitates debugging and binary unpgradability,
minimize potential code bloat.
6. Minimize compilation dependencies between files.
Inheritance and Object-Oriented Design.
1. Make sure public inheritance models "Is-a".
virtual function means interfaces must be inherited.
non-virtual function means both interfaces and implementations must be inherited.
2. Avoid hiding inherited names.
all functions named FUNC in the base class are hidden by the functions named FUNC in the
derived class.
To make hidden names visible again, employ using declarations or forwarding functions;
3. Differentiate between inheritance of interface and inheritance of implementation.
4. Consider alternatives to virtual functions.
a. Template method. Still uses virtual mechanism.
b. Strategy pattern. using Function Pointer. maybe weaken the class's encapsulation.
c. using boost::function. then we can use function pointer, function object, member function pointer.
d. replace virtual function in one hierarchy with virtual functions in another hierarchy. this is combination
of strategy pattern and bridge pattern.
5. Never redefine an inherited non-virtual function.
6. Never redefine a function's inherited default parameter value.
distinguish between static type and dynamic type.
An object's static type is the type you declare it to have in the program text.
An object's dynamic type is determined by the type of the object to which it refers.
Dynamic type indicates how it will behave.
Virtual functions are dynamically bound. while default parameter value is statically bound.
7. Model has-a or is-implemented-in-terms-of through composition.
Composition is the relationship between types that arises when objects of one type contain objects of another type.
In the application domain, composition means has-a. In the implementation domain , composition means is-implemented-in
terms-of.
8. Use private inheritance judiciously
Empty base optimization(EBO).
9. Use multiple inheritance judiciously
Templates and Generic Programming
ability to write code that is independent of the types of objects being manipulated.
1. Understand implicit interfaces and compiletime polymorphism.
For classes, interface are explicit and centered on function signatures. polymorphism occurs at runtime
through virtual functions.
For template parameters, interfaces are implicit and based on valid expressions. polymorphism occurs during
compilation through template instantiation and function overloading resolution.
2. Understand the two meanings of typename
as template type parameter, typename and class mean the same thing.
use typename to identify nested dependent type names.
3. Know how to access names in templatized base classes.
Note specialization of template.
In derived class templates , refer to names in base class templates via a "this->" prefix, via using declarations,
via an explicit base class qualification.
4. Factor parameter-independent code out of templates.
Template generate multiple classes , so any template code not dependent on a template parameter causes bloat.
Bloat due to non type template parameters can often be eliminated by replacing template parameters with function
parameters or class data members.
Bloat due to type parameters can be reduced by sharing implementations for instantiation types with identical binary
representations.
5. Use member function templates to accept all compatible types.
Member function can themselves be function template specifying additional