Accustoming yourself to C++

2 prefer consts, enums, and inlines to #define.

  1. One special case need to be noted is class-specific constants. check this question in stackOverflow
  2. difference between declaration and definition. Check this question in stackOverflow

3 Use const whenever possible

  1. declaring an iterator const is like declaring a pointer const. const std::vector<int>::iterator iter = ..., here iter acts like a T* const. If you want an iterator that points to something that can’t be modified, you want a const_iterator.
  2. when const and non-const member functions have essentially identical implementations, code duplication can be avoided by having the non-const version call the const version.

4 Make sure that objects are initialized before they’re used.

  1. For constructor of a class, prefer using initialization list to assignment inside the body of the constructor.
  2. order in which an object’s data is initialized: base classes are initialized before derived classes, and within a class, data members are initialized in the order in which they are declared.
  3. avoid initialization order problems across translation units by replacing non-local static objects with local static objects.

Constructors, destructors, and assignment operators

  1. To disallow functionality automatically provided by compilers, declare the corresponding member functions private and give no implementations. Using a base class like Uncopyable is one way to do this. [For c++11, you could use = delete.]
  2. declare desturctors virtual in polymorphic base classes. If a class has any virtual functions, it should have a virtual destructor.
  3. prevent exceptions from leaving destructors. If function called in a destructor may throw, the destructor should catch any exceptions, then swallow them or terminate the program.
  4. don’t call virtual functions during construction or destruction.
  5. have assignment operators return a reference to *this
  6. make sure operator= is well-behaved when an object is assigned to itself: comparing addresses of source and target objects, careful statement ordering, and copy-and-swap.

Resource Management

  1. To prevent resource leaks, use RAII(resource Acquisition Is Initialization) oejects that acquire resources in their constructors and release them in their destructors.( auot_ptr and tr1::shared_ptr)[ For c++11, shared_ptr and unique_ptr.]
  2. when you use [] in new, remember use delete []
  3. store newwd objects in smart pointers in standalone statements. Failure to do this can lead to subtle resource leaks when exceptions are thrown.
  4. Prefer pass-by-reference-to-const over pass-by-value. It’s typically more efficient and it avoids the slicing problem. The rule doesn’t apply to built-in types and STL iterator and function object types.
  5. don’t try to return a reference when you must return an object.
  6. declare date members private; protected is no more encapsulated than public
  7. prefer non-member non-friend functions to member functions. Doing so increase encapsulation, packaging flexibility, and functional extensibility.
  8. declare non-member functions when type conversions should aply to all parameters. For example, define operator* for class Rational.
  9. Swap
    1.  provide a `swap` member function when `std::swap` would be _inefficient_ for your type. Make sure your `swap` doesn’t throw exceptions
    
    1. if you offer a member swap, also offer a non-member swap that calls the member. For classes(not templates), specialize std::swap(total template specialization).
    2. when calling swap, employ a using delcaration for std::swap, then call swap without namespace qualification.
    3. If’s fine to totally specialize std templates for user-defined types, but never try to add something completely new to std.

Implementations

  1. postphone variable definitions as long as possible.
  2. avoid casts whenever practical, especially dynamic_casts in performance-sensitive code. If a design requires casting, try to develop a cast-free alternative.
  3. avoid returning handles (references, pointers, or iterators) to object internals. It increase encapsulation, helps const member functions act const, and minimizes the creation of dangling handles.
  4. strive for exception-safe code
    Exception-safe functions leak no resources and allow no data structures to become corrupted, even when exceptions are thrown. Such functions offer the basic, strong, or nothrow guarantees.
  5. Limit most inlining to small, frequently called functions. This facilitates debugging and binary upgradability, minimizes potential code bloat, and maximizes the chances of greater program speed.
  6. The general idea behind minimizing compilation dependencies is to depend on declarations instead of definitions. Two approaches based on this idea are Handle classes and Interface classes.
    *   **forward declaration**, check the answers [1](http://stackoverflow.com/questions/553682/when-can-i-use-a-forward-declaration) [2](http://stackoverflow.com/questions/4757565/c-forward-declaration) in stackOverlfow.
    
    • pimpl idiom(pointer to implementation), check the answers 1 2 3(iosfwd)* pimpl v.s. interface, check stackOverflow 4

Ihheritance and Object-Oriented Design

  1. public inheritance means “is-a”. Everything that applies to base classes must also apply to derived classes.
  2. avoid hiding inherited names

    1.  for pubic inherit, if you inherit from a base class with overloaded functions and you want to redefine or override only some of them, you need to include a `using` declaration for each name you’d otherwise be hiding. If you don’t, some of the names you’d like to inherit will be hidden.(why? first check the function name, then the type of parameter. See _c++ primer_, chap 15.6)
    
    1. for private inherit, if you don’t want to inherit all of them, you could use inline forwarding functions instead of using declaration.
  3. differentiate between inheritance of interface and inheritance of implementation

    1.  The purpose of declaring a **pure virtual function** is to have derived classes inherit a function _interface only_.
    
    1. The purpose of declaring a simple virtual function is to have derived classes inherit a function interface as well as a default implementation(sometimes maybe dangerous, could separate functions for providing interface and default implementation)
    2. The purpose of declaring a non-virtual function is to have derived classes inherit a function interface as well as a mandatory implemntation.
  4. Consider alternatives to virtual functions

    *   use the **non-virtual interface idiom**(NVI idiom), a form of the  _Template Method design pattern_ that wraps public non-virtual member functions around less accessible virtual functions. Details of NVI in [wiki](https://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface)(noted: derived classes could redefining private virtual functions)
    
    • replace virtual functions with function pointer data members, a stripped-down manifestation of the Strategy design patternwiki.
    • Replace virtual function with tr1::function data members, thus allowing use of any callable entity with a signature compatible with what you need.This, too, is a form of the Strategy desing pattern.[For c++11, it’s std::function and std::bind]
    • replace virtual functions in one hierarchy with virtual functions in another hierarchy. This is the conventional implementation of the Strategy design pattern.
  5. never redefine an inherited non-virtual function. cause non-virtual functions are statically bound.

  6. never redefine an inherited default parameter value, because default parameter values are statically bound, while virtual functions- the only functions you should be overriding - are dynamically bound.
  7. Model ‘has-a’ or ‘is-implemented-in-terms-of’ through composition.
  8. private inheritance means is-implemented-in-terms-of. It’s usually inferior to composition, but it makes sense when a derived class needs to composition(mixture of public inheritance and containment), but it makes sense when a derived class needs access to protected base class members or needs to redefine inherited virtual functions. private inheritance can enable the empty base optimization(“empty” class never have non-static data members, but contain typedefs, enums, static data members, or non-virtual functions), which could minimize object sizes.
  9. Multiple inheritance can lead to new ambiguity issues and to the need for virtual inheritance. Virtual inheritance imposes costs in size, speed, and complexity of initialization and assignment. It’s most practical when virtual base classes have no data.
    One scenario involves combining public inheritance from an Interface class with private inheritance from a class that helps with implementation.

Templates and Generic Programming

  1. both classes and templates support interfaces and polymorphism

    1.  classes: interfaces are explicit and centered on function signatures. Polymorphism: runtime through virtual functions
    
    1. template parameters: interfaces are implicit and based on valid expression. Polymorphism: compilation through template instantiation and function overloading resolution.
  2. when declaring template paramters, class and typename are interchangeable. use typename to identify nested dependent type names, except in base class lists or as a base class identifier in a member initialization list.

  3. In derived class templates, refer to names in base class templates via a this-> prefix , via using declarations, or via an explicit base class qualification.
  4. factor parameter-independent code out of templates: templates generate multiple classes and multiple functions, which may cause bloat. about non-type parameter, check this in stackOverflow

    1.  bloat due to non-type template parameters can often be eliminated by replacing template parameters with funciton parameters or class data members.
    
    1. bloat due to parameters can be reduced by sharing implementations for instantiation types with identical binary representations.
  5. use member function templates to generate functions that accept all compatible types.(kind of similar to Covariance and Contravariance in scala) (could use private build-in pointer the control the conversion, thus make it “covariance”).
    If you declare member templates for generalized copy construction or generalized assignment, you’ll still need to declare the normal copy constructor and copy assignment operator, too.

  6. When writing a class template that offers functions related to the template that support implicit type conversions on all parameters(see list 8 in Resource Management part), define thoses functions as friends inside the class template.7. Traits classes make information about types available during compilation. They’re implemented using templates and template specializations. In conjunction with overloading, traits classes make it possible to perform compile-time if…else tests on types.(create a set of overloaded “worker” functions or function templates that differ in a traits parameter).
  7. Template metaprogramming(TMP) could shift work from runtime to compile-time, thus enabling earlier error detection and higher runtime performance. One “hello word”-type example:

    template<unsigned n>
    

    struct Factorial{

    enum{ value = n * Factorial<n-1>::value};
    

    };
    template<>
    struct Factorial<0>{

    enum {value = 1};
    

    }

Customizing new and delete

  1. understand the behavior of the **new-handler

    1.  well-designed new-handler function must do one of the following:
    
            *   Make more memory available
    *   install a different new-handler
    *   deinstall the new-handler
    *   throw an exception
    *   not return(abort or exit)
    
    2.  `set_new_hadler` allows you to specify a function to be called when memory allocation requests cannot be satisfied.
    
    1. Nothrow new is of limited utility, because it applies only to memory allocation. subsequent constructor calls may still throw exceptions.
  2. few reasons to write custom versions of new and delete.

    *   to detect usage errors
    
    • to collect statistics about the use of dynamically allocated memory
    • to increase the speed of allocation and deallocation
    • to reduce the space overhead of default memory management
    • to compensate for suboptimal alignment in the default allocator
    • to cluster related objects near one another
    • to obtain unconventional behavior.
  3. operator new should contain an infinite loop trying to allocate memory, should call the new-handler if it can’t satisfy a memory request, and should handle requests for zero bytes. Class-specific versions should handle requests for larger blocks than expected(use standard operator new).
    operator delete should do nothing if passed a pointer that is null. Class-specific versions should handle blocks that are larger than expected.(use standard operator delete)

  4. when you are write a placement version of operator new, be sure to write the corresponding placement version of operator delete. If you don’t, your program may experience subtle, intermittent memory leaks.
    When you declare placement versions of new and delete, be sure not to unintentionally hide the normal versions of those functions.

Miscellany

  1. pay attention to compiler warnings, understand exactly what it’s trying to tell you.
  2. Familiarize yourself with Boost.