Sunday, January 29, 2017

Effective C++ 50 Items Notes




Effective C++ 50 Items

  1. Prefer const and inline to #define
    1. const
      1. in class
      2. static member
      3. enum trick
    2. macro
      1. use inline function instead
      2. use template together with the inline function
  2. Prefer <iostream> to <stdio.h>
    1. <iostream>: functions are in the std namespace.
    2. <iostream.h> functions are in the global scope.
  3. Prefer new and delete to malloc and free
    1. with malloc/free, constructors and destructors are not involved and this is not good.
  4. Prefer C++ style comments
  5. Use the same form in corresponding uses of new and delete
    1. pay attention to typedef, especially when the array is involved in the definition.
  6. Use delete on pointer members in destructors
    1. adding a pointer member almost always requires each of the following:
      1. initialization of the pointer in each of the constructor.
      2. deletion of the existing memory and assignment of new memory in the assignment operator.
      3. deletion of the pointer in the destructor.
  7. Be prepared for out-of-memory condition
    1. assertions are checked in debug mode when NDEBUG isn't defined.
    2. a well-defined new-handler function must do one of the following
      1. make more memory available
        1. one way to implement this strategy is to allocate a large block of memory at program start-up, then release it in the first time the new handler is invoked.
      2. install a different new-handler
      3. de-install the new-handler
        1. pass the null pointer to set_new_handler
      4. throw an exception
      5. not return
        1. call abort or exit
  8. Adhere to convention when writing operator new and operator delete
    1. operator new actually tries to allocate memory more than once.
    2. only when the pointer to the error-handling function is null does operator new throw an exception.
    3. operator new is inherited by subclasses.
    4. new T[5] calls operator new[](count) where count = sizeof(T) * 5 + overhead.
    5. because the operator new or operator new[] can be called by a subclass, essentially, we cannot know the exact size of the element, it can be either sizeof(base) or the sizeof(derived)
  9. Avoid hiding the "normal" form of new
    1.  write a class-specific operator new that supports the normal invocation form
    2. an alternative is to provide a default parameter value for each additional parameter you add to operator new.
  10. write operator delete if you write operator new
    1. the main reason we want to overload the operator new and operator delete is performance.
    2. the default operator new/delete may need to handle the communication between these two operators and additional header is needed.
    3. we may need to have a virtual function in the class to make the customized operator delete work.
  11. Declare a copy constructor and an assignment operator for classes with dynamically allocated memory.
    1. write your own copy constructor and assignment operator if you have any pointers in your class.
  12. Prefer initialization to assignment in constructors
  13.  List members in an initialization list in the order in which they are declared
    1. class members are initialized in the order of their declaration in the class.
    2. base class data members are initialized before derived class data members.
  14. Make sure base classes have virtual destructor
    1. you have a class that you'd like to be abstract, but you don't happen to have any functions that are pure virtual. In this situation, you can declare a pure virtual destructor.
  15. Have operator= return a reference to *this
  16. Assign to all data members in operator=
    1. be careful about the implementation in the derived class. Most of the time, we need to explicitly call the operator=, copy constructor of the base class.
  17. Check for assignment to self in operator=
  18. Strive for class interfaces that are complete and minimal
  19. Differentiate among member functions, non-member functions and friend functions
    1. The biggest difference between member functions and non-member functions is that member functions can be virtual and non-member functions cannot.
    2. virtual functions must be members
    3. operator>> and operator<< are never members.
    4.  Only non-member functions get type conversions on their left-most argument.
    5. Everything else should be a member function.
  20. Avoid data members in the public interface.
  21. Use const whenever possible
    • mutable keyword
    • const member functions
      • bitwise constness
      • conceptual constness
  22. Prefer pass-by-reference to pass-by-value
  23. Don't try to return a reference when you must return an object
  24. Choose carefully between function overloading and parameter defaulting
  25. Avoid overloading on a pointer and a numerical type
    • Think about the following example
      • void f(int x);
      • void f(string *ps);
      • call f(0) 
    • member function template
  26. Guard against potential ambiguity
  27. Explicitly disallow use of implicitly generated member functions you don't want
    • declare the function private
    • do not implement the function
  28. Partition the global namespace
  29. Avoid returning "handlers" to internal data
    • conversion of types
  30. Avoid member functions that return non-const pointers or reference to members less accessible than themselves.
  31. Never return a reference to a local object or to a dereference pointer initialized by new within the function.
  32. Postpone variable definitions as long as possible
  33.  Use inlining judiciously
    • The inline directive, like register, is a hint to compilers, not a command.
  34. Minimize compilation dependencies between files
    • Avoid using objects when object references and pointers will do
    • use class declarations instead of class definitions whenever you can.
    • don't #include header files in your header files unless your headers won't compile without them
  35. Make sure public inheritance models "is-a"
  36. Differentiate between inheritance of interface and inheritance of implementation.
    • the purpose of declaring a pure virtual function is to have derived classes inherit a function interface only.
    • it is possible to provide a definition for a pure virtual function. But the only way to call it would be to fully specify the call with the class name.
    • The purpose of declaring a simple virtual function is to have derived classes inherit a function interface as well as a default implementation.
    • the purpose of declaring a non-virtual function is to have derived classes inherit a function interface as well as a mandatory implementation. 
  37. Never redefine an inherited non virtual function
  38. Never redefine an inherited default parameter value
    • virtual functions are dynamically bound but default parameter values are statically bound.
    • the default parameters are determined during the compilation time. The reason for this behaviour is efficiency.
  39. Avoid casts down the inheritance hierarchy
  40. Model "has-a" or "is-implemented-in-term-of" through layering.
  41. Differentiate between inheritance and templates
    • Try to answer the question: does the type T affect the behaviour of the class? If T does not affect the behaviour, you can use a template. If T does affect the behaviour, you'll need virtual functions and you'll therefore use inheritance.
  42. Use private inheritance judiciously
    • In contrast to public inheritance, compilers will generally not convert a derived class object into a base class object if the inheritance relationship between the classes is private.
    • Private inheritance means is-implemented-in-terms-of.
    •  Private inheritance is purely an implementation technique.
    • Private inheritance means that implementation only should be inherited; interface should be ignored.
    • Private inheritance means nothing during software design, only during software implementation.
  43. Use multiple inheritance judiciously
  44. Say what you mean; understand what you are saying
    • A common base class means common traits.
    • Public inheritance means "is-a".
    • Private inheritance means "is-implemented-in-terms-of".
    • Layering or composition means "has-a" or "is-implemented-in-terms-of"
    • A pure virtual function means that only the function's interface is inherited.
    • A simple virtual function means that the function's interface plus a default implementation is inherited.
    • A non-virtual function means that the function's interface plus a mandatory implementation is inherited.
  45. Know what functions C++ silently writes and calls
  46. Prefer compile-time and link-time errors to runtime errors
  47. Ensure that non-local static objects are initialized before they're used
    • singleton pattern
    • the order of non-local static objects
    • use function that returns the reference of a static variable
  48. Pay attention to compiler warnings
  49. Familiarize yourself with the standard library
  50. Improve your understanding of C++












No comments:

Post a Comment