What you will learn in this course

This intensive seminar, based on material in Meyers' landmark books (Effective C++, More Effective C++, and Effective STL), explains how to use C++ effectively: how to create libraries and programs that are correct, efficient, portable, maintainable, and extensible.

Course highlights

Participants will gain:
  • Knowledge of the rules of thumb applied by expert C++ programmers as they design and implement software systems.
  • An understanding of the proper application of C++'s many features, e.g., member and non-member functions, templates, inheritance, virtual and non-virtual functions, namespaces, etc.
  • Insights into how to effectively combine language features to achieve desired behavior.

Format: Lecture, question/answer, and group design and problem-solving exercises. There is no hands-on programming, but participants are welcome to use their computers to experiment with the course material as it is presented.

Course outline and topics

const:
  • The value of const
  • const, pointers, string literals, and indirection
  • const, pass-by-value, and return-by-value
  • bitwise const vs. conceptually const member functions
  • Casting away const
  • const and object lifetimes
  • const vs. #define vs. "the enum hack"
Resource Management:
  • Use objects to manage resources
  • Resource acquisition is initialization (RAII)
  • std::auto_ptr
  • std::tr1::shared_ptr
  • TR1 and Boost
  • Think carefully about copying behavior in resource-managing classes
  • Store resources in objects in standalone statements
Constructors, Destructors, and Assignment Operators:
  • Know what functions C++ silently writes and calls
  • Explicitly disallow use of implicitly generated member functions you don't want:
    • Declaring functions private
    • Inheriting from a base class declaring them private
  • List members in an initialization list in declaration order
Handle copying in classes with pointers:
  • Handling the functions yourself
  • Using resource-managing objects
  • Make destructors virtual in base classes
  • Virtual functions and object layout
  • Prevent exceptions from leaving destructors
  • Handle assignment to self in operator=:
  • The problem of aliasing
  • Checking for assignment to self
  • Using resource-managing objects
  • Self-assignment and exception-safety
  • Assign to all data members in operator=:
  • Partial assignments
  • The problem of inheritance
  • The copy construction analogue
Further Class Design:
  • Be wary of user-defined conversion functions
  • Avoid returning "handles" to internal data
  • Prefer non-member non-friend functions to member functions:
    • The value of encapsulation
    • How removing member functions increases class encapsulation
    • Using namespaces to associate classes and functions
  • Declare non-member functions when type conversions should apply to all parameters
  • If you overload binary operator op, overload op= too
  • Choose carefully between function overloading and parameter defaulting
  • Guard against potential ambiguity
Inheritance And Object-oriented Design:
  • Make sure public inheritance models "isa"
  • Inheritance and intuition
  • Runtime vs. compile-time error detection
  • Inheritance and substitutability
Differentiate between inheritance of interface and inheritance of implementation:
  • The meaning of pure virtual functions
  • The meaning of "impure" virtual functions
  • The meaning of nonvirtual functions
  • Never redefine an inherited nonvirtual function
Avoid casts down the inheritance hierarchy
  • Avoidance techniques
  • Using RTTI for safe downcasting
  • dynamic_cast
  • typeid
  • RTTI and tr1::shared_ptrs
  • Model "has-a" or "is-implemented-in-terms-of" through containment
  • Use private inheritance judiciously
  • Use multiple inheritance judiciously:
    • MI and ambiguity
    • Virtual base classes
    • Initialization
    • Dominance
  • Software evolution and MI
  • Understand implicit interfaces and compile-time polymorphism:
    • Explicit interfaces
    • Implicit interfaces
    • Making implicit interfaces explicit
    • Runtime vs. compile-time polymorphism
Concepts and Architecture of the STL:
  • Arrays and pointers, half-open ranges
  • Generalizing pointers to iterators
  • Generalizing arrays to sequences
  • Algorithms
  • Conventions and extensibility
  • Function objects
  • Overview of standard and TR1 containers
  • The behavior of remove
Efficiency:
  • The 80-20 rule and program profiling.
  • Language issues:
    • Eliminating unnecessary temporary objects:
      • Pass by reference-to-const instead of by value.
      • Defer object definitions as long as possible.
      • Prefer initialization to assignment in constructors.
      • Consider overloading to avoid implicit type conversions.
      • Consider using op= instead of op.
      • Facilitate the return value optimization.
      • Consider a more C-like design.
Don't try to return a reference when you must return an object:
  • Returning a reference to a local object.
  • Returning a reference to a heap-allocated object.
  • Returning a reference to a local static object.
The pros and cons of inlining:
  • Inlining and compiler optimization.
  • Automatic inlining.
  • Linktime inlining.
  • When custom memory managers make sense.
Library issues:
  • Use reserve to minimize memory reallocations in vector and string.
  • Using "the swap trick" to perform "shrink to fit."
  • Prefer range member functions to single-element versions for sequence containers.
  • Prefer function objects to functions.
  • Why sort is typically faster than qsort.
  • Why sorted vectors can be superior to sets and maps for lookup-intensive applications.
  • std::binary_search vs. std::lower_bound vs. std::equal_range
  • STL containers based on hash tables.
Reference Counting:
  • A reference-counted string implementation.
  • How changing the implementation changed the interface.
  • How threading issues can turn an optimization into a pessimization.
  • Additional Efficiency Topics
Programming with Exceptions:
  • EH 101
  • try, throw, catch, stack unwinding
  • Exception specifications
  • Function try blocks
  • The real challenge of programming with exceptions
  • Strive for exception-safe code
  • Definition of "exception-safe"
  • The basic, strong, and nothrow guarantees
  • Exception specifications and exception-safety guarantees
  • Approaches to the strong guarantee
  • Careful statement ordering
  • Copy and swap
  • Dependencies among exception-safety guarantees
  • Exercise: making exception-unsafe code exception-safe
  • Preventing resource leaks in constructors
  • The differences between passing parameters to functions and moving exceptions from throw sites to catch clauses.
  • Understanding the performance costs of exception handling.
  • Epilogue: Programming In The Future Tense
  • Sources for Additional Information