[C++][Chap. 5] Implementations

[content]

Item 26: Postpone variable definition as long as possible

DO: Declare, define and initialize variables right before when you need them.

DO: Trade-off between declaring variables inside and outside loops
1. Inside: n constructors + n destructors.
2. Outside: 1 constructor + 1 destructor + n assignments.
Approach 2 is generally more efficient if an assignment cost is less than a constructor.

WHY: Postponing variable definition as long as possible. It increases program clarity and efficiency.

Item 27: Minimize casting

Different syntax for casting:
1. (T) expression; C-style cast.
2. T(expression); Function-style cast.
3. const_cast<T>(expression); Cast away const-ness.
4. dynamic_cast<T>(expression);
Primary used for safe down-casting.
This cloud incur significant runtime cost. In C++.
A single object could have more than one address, (The address for its base class object can be different from that for the derived class object). Therefore, we need to use dynamic_cast instead of old-style cast.
dynamic_cast could use strcmp to compare class names.
5. reinterpret_cast<T>(expression); Used for low-level casts, e.g. casting int to pointer.
6. static_cast<T>(expression);
Used to force implicit conversion.
static_cast on *this could result in constructing a new copy of the object.

DO: Avoid casts whenever practical, especially dynamic_cast.

DO: Prefer C++ style casts to old-style casts.

WHY: Casting in C++ less necessary and more dangerous than in other languages.

Item 28: Avoid returning “handles” to object internals

DO: References, pointers and iterators are all handles (ways to get other objects). Avoid returning them to internal objects.

WHY: Risk of compromising encapsulation.

WHY: Help keep const member act const.

Item 29: Strive for exception-safe code

DO: If exception is thrown, exception-safe function should not leak resources and corrupted existing data structures.

Three levels of guarantee an exception-safe code can offer:
1. The basic guarantee: No objects or data structure become corrupted, all objects are in an internally consistent state. But the exact state of the program may not be predictable.
2. The strong guarantee: if an exception is thrown, the state of the program is unchanged. Calls to such functions are atomic.
3. The no-throw guarantee: function never throws exception.

DO: One technique to achieve exception-safe code is “copy and swap”.

DO: A function can usually only offer a guarantee no stronger than the weakest guarantee of functions it calls.

Item 30: Understand the ins and outs of inlining

Inline is a request to compilers, not a command. Compilers can refuse to do inline for a function.

DO: If we put the member function definition in the class definition, we implicitly tell compilers to do inline for the function.

DO: Put inline in header file. Inlining is done during compilation. Compilers need to know the definition of the function to inline it.

DO: Keep inline function small. It is a trade-off between source code size and function call stack depth. Also, there is no break point you can set for inline function.

DO: No inline for virtual functions. Inline is done in compilation time, but virtual function can only be known in run time.

DO: Library designers must evaluate the impact of inline. Inline function means exposing function definition to library users.
1. If the function is changed, library users need to re-compile to integrate with the new function.
2. If the function is not inline, library users just need to re-link the function.

Item 31: Minimize compilation dependencies between files

DO: Use declaration forward to separate interfaces from implementations.
1. Use reference and pointer instead of the actual object. Use plmpl idiom. (“pointer to implementation”)
2. Replace the dependencies on definition with dependencies on declaration
3. Provide separate header files for declarations and definition

WHY: We reply on forward definition mainly because,
1. Layering inversion (referring to a type that is defined higher in the dependency stack) or circular references between types
2. Need to declare a class to express friend relationship
3. Reducing the amount of source that need to be compiled
4. User pimpl pattern to preserve ABI (application binary interface) backward compatibility

DO: Do not use declaration forward too much. It could lead to significant maintenance problems.

Leave a Reply

Your email address will not be published. Required fields are marked *