You are previewing More Exceptional C++.
O'Reilly logo
More Exceptional C++

Book Description

Organized in a practical problem-and-solution format, More Exceptional C++ picks up where the widely acclaimed Exceptional C++ leaves off, providing successful strategies for solving real-world problems in C++. Drawing from years of in-the-trenches experience, Herb Sutter provides tested techniques and practical solutions for programmers designing modern software systems with C++, from small projects to enterprise applications.

Built around forty programming puzzles, More Exceptional C++ helps you understand the rules and issues critical to successful software design and development in C++. New themes included in this sequel place a strong emphasis on generic programming, memory management, and using the C++ standard library, including coverage of important techniques like traits and predicates. Also included are guidelines and considerations to remember when using standard containers and algorithms--topics rarely covered in-depth in other sources.

Readers will find solutions to such important questions as:

  • What pitfalls might you encounter when using std::map and std::set, and how can you safely avoid them?

  • What kinds of predicates are safe to use with the STL, what kinds aren't, and why?

  • What techniques are available for writing powerful generic template code that can change its own behavior based on the capabilities of the types it's given to work with?

  • When and how should you optimize your code? Why can (and do) fancy optimizations get us into trouble? And how can some of these answers change if you're writing multithread-safe code?

  • Does exception safety affect class design, or can it be retrofitted in as an afterthought?

  • How can you avoid the Siamese Twin problem when combining inheritance-based libraries from different vendors?

  • How can you safely use auto_ptr, and then use common design patterns to adapt it to avoid common pitfalls? Can you use auto_ptr as a class member? What must you know before you elect to use it that way?

  • Plus one of the most frequently recurring questions about modern C++: When and how should you use namespaces, anyway?

A must-have for the serious programmer, More Exceptional C++ provides a thorough and pragmatic understanding of the language while showing you how to write exceptional code in C++.



020170434XB11092001

Table of Contents

  1. Copyright
    1. Dedication
  2. Foreword
  3. Preface
    1. What's “More?”
    2. What I Assume You Know
    3. How to Read This Book
    4. Namespaces, Typename, References, and Other Conventions
    5. Acknowledgments
  4. Generic Programming and the C++ Standard Library
    1. 1. Switching Streams
      1. Solution
        1. The Tersest Solution
        2. Toward More-Flexible Solutions
        3. Method A: Templates (Compile-Time Polymorphism)
        4. Method B: Virtual Functions (Run-Time Polymorphism)
        5. Sound Engineering Principles
    2. 2. Predicates, Part 1: What remove() Removes
      1. Solution
        1. What remove() Removes
    3. 3. Predicates, Part 2: Matters of State
      1. Solution
        1. Unary and Binary Predicates
        2. The Next Step: Stateful Predicates
        3. Follow-Up Question
    4. 4. Extensible Templates: Via Inheritance or Traits?
      1. Solution
        1. Requiring Member Functions
        2. Constraints Classes
        3. Requiring Inheritance, Take 1: IsDerivedFrom1 Value Helper
        4. Requiring Inheritance, Take 2: IsDerivedFrom2 Constraints Base Class
        5. Requiring Inheritance, Take 3: A Merged IsDerivedFrom
        6. Selecting Alternative Implementations
        7. Requirements versus Traits
        8. Inheritance versus Traits
    5. 5. Typename
      1. Solution
        1. 1. Use typename for Dependent Names
        2. 2. The Secondary (and Subtle) Point
        3. Postscript
    6. 6. Containers, Pointers, and Containers That Aren't
      1. Solution
        1. Prelude
        2. Why Take Pointers or References into Containers?
        3. How Could the Code Be Improved?
        4. When Is a Container Not a Container?
        5. Which Brings Us to the Awkward Part
        6. The Life and Times of vector<bool>
        7. Proxied Containers and STL Assumptions
        8. Beware Premature Optimization
        9. So What Should You Do?
    7. 7. Using vector and deque
      1. Solution
        1. Using a vector as an Array: A Motivating Example
        2. A Fly in the Ointment?
        3. In Most Cases, Prefer Using vector
        4. The Incredible Shrinking vector
        5. Summary
    8. 8. Using set and map
      1. Solution
        1. Associative Containers: Review
        2. The Key Requirement
        3. A Motivating Example
        4. Option #1: Say “const Means const!” (Insufficient)
        5. Option #2: Say “Always Change Keys Using Erase-Then-Insert” (Better, But Still Insufficient)
        6. What About set?
        7. The Key Requirement (Reprise)
    9. 9. Equivalent Code?
      1. Solution
        1. 1. A macro.
        2. 2. A function.
        3. 3. An object.
        4. 4. A type name.
        5. 1. A macro.
        6. 2. An object (possibly of a built-in type).
        7. 3. A value, such as an address.
        8. Some Effects of Side Effects
        9. Scissors, Traffic, and Iterators
    10. 10. Template Specialization and Overloading
      1. Solution
        1. Explicit Specialization
        2. Partial Specialization
        3. Function Template Overloading
    11. 11. Mastermind
      1. Simplified Rules Summary
      2. Solution
        1. Solution #1
          1. ChoosePeg
          2. CountPlace
          3. CountColor
          4. Summary
        2. Solution #2
          1. Combination
          2. ColorMatch
          3. Summary
        3. Comparing the Solutions
  5. Optimization and Performance
    1. 12. inline
      1. Solution
        1. Just Say “No for Now”
        2. What About Computation-Intensive Tasks (Such as Numeric Libraries)?
        3. What About Accessors?
    2. 13. Lazy Optimization, Part 1: A Plain Old String
      1. Solution
        1. Implementing Original::String
        2. Aside: What's the Best Buffer Growth Strategy?
    3. 14. Lazy Optimization, Part 2: Introducing Laziness
      1. Solution
    4. 15. Lazy Optimization, Part 3: Iterators and References
      1. Solution
        1. Writing operator[] for Shareable Strings
        2. Key Notion: An “Unshareable” String
        3. Summary
    5. 16. Lazy Optimization, Part 4: Multithreaded Environments
      1. Solution
        1. Thread-Safety Problems with Copy-on-Write (COW)
        2. Protecting COW Strings
        3. Some Empirical Results
        4. Summary
  6. Exception Safety Issues and Techniques
    1. 17. Constructor Failures, Part 1: Object Lifetimes
      1. Solution
        1. Function Try Blocks
        2. Object Lifetimes and What a Constructor Exception Means
    2. 18. Constructor Failures, Part 2: Absorption?
      1. Solution
        1. I Can't Keep No Caught Exceptions
        2. A Step Toward Morality
        3. Aside: Why Does C++ Do It That Way?
        4. Morals About Function Try Blocks
        5. Morals About Safe Coding
        6. That's Just the Way It Is
        7. A Final Word: Failure-Proof Constructors?
        8. Summary
    3. 19. Uncaught Exceptions
      1. Solution
        1. Recapping uncaught_exception()
        2. Background: The Problem with Throwing Destructors
        3. The Wrong Solution
        4. Why the Wrong Solution Is Unsound
        5. Why the Wrong Solution Is Immoral
        6. The Right Solution
    4. 20. An Unmanaged Pointer Problem, Part 1: Parameter Evaluation
      1. Solution
        1. Recap: Evaluation Orders and Disorders
        2. Some Function Call Exception Safety Problems
    5. 21. An Unmanaged Pointer Problem, Part 2: What About auto_ptr?
      1. Solution
        1. Aside: A Non-Solution
        2. A Limited Solution
        3. Generalizing the auto_ptr_new() Solution
        4. A Better Solution
        5. Summary
        6. Acknowledgments
    6. 22. Exception-Safe Class Design, Part 1: Copy Assignment
      1. Solution
        1. Review: Exception Safety Canonical Forms
        2. Analyzing the Cargill Widget Example
        3. A General Technique: Using the Pimpl Idiom
        4. A Potential Objection, and Why It's Unreasonable
        5. Conclusion 1: Exception Safety Affects a Class's Design
        6. Conclusion 2: You Can Always Make Your Code (Nearly) Strongly Exception-Safe
        7. Conclusion 3: Use Pointers Judiciously
    7. 23. Exception-Safe Class Design, Part 2: Inheritance
      1. Solution
        1. Is-Implemented-In-Terms-Of
        2. How to Implement IIITO: Inheritance or Delegation?
        3. Exception Safety Consequences
        4. Summary
  7. Inheritance and Polymorphism
    1. 24. Why Multiple Inheritance?
      1. Solution
    2. 25. Emulating Multiple Inheritance
      1. Solution
        1. Drawbacks
    3. 26. Multiple Inheritance and the Siamese Twin Problem
      1. Solution
        1. How to Separate Siamese Twins
    4. 27. (Im)pure Virtual Functions
      1. Solution
        1. 1. Pure Virtual Destructor
        2. 2. Force Conscious Acceptance of Default Behavior
        3. 3. Provide Partial Behavior
        4. 4. Work Around Poor Compiler Diagnostics
    5. 28. Controlled Polymorphism
      1. Solution
  8. Memory and Resource Management
    1. 29. Using auto_ptr
      1. Solution
        1. Problem: Arrays and auto_ptr Don't Mix
        2. Aside on a Non-problem: Zero-Length Arrays Are Okay
        3. Option 1: Roll Your Own auto_array
          1. Option 1 (a): … By Deriving from auto_ptr (Score: 0 / 10)
          2. Option 1 (b): … By Cloning auto_ptr Code (Score: 8 / 10)
        4. Option 2: Use the Adapter Pattern (Score: 7 / 10)
        5. Option 3: Replace auto_ptr with Hand-Coded Exception-Handling Logic (Score: 1 / 10 )
        6. Option 4: Use a vector Instead of an Array (Score: 9.5 / 10 )
    2. 30. Smart Pointer Members, Part 1: A Problem with auto_ptr
      1. Solution
        1. Recap: Problems of Pointer Members
        2. What About auto_ptr Members?
        3. Variations on a Theme by ValuePtr
    3. 31. Smart Pointer Members, Part 2: Toward a ValuePtr
      1. Solution
        1. A Simple ValuePtr: Strict Ownership Only
        2. Copy Construction and Copy Assignment
        3. Templated Construction and Templated Assignment
        4. Adding Extensibility Using Traits
        5. Applying Traits
        6. ValuePtr with Traits
        7. A Usage Example
        8. Summary
  9. Free Functions and Macros
    1. 32. Recursive Declarations
      1. Solution
        1. Function Pointers: Recap
        2. A Brief Look at State Machines
        3. How Can a Function Return a Pointer to Itself?
        4. A Correct and Portable Way
        5. Coda
    2. 33. Simulating Nested Functions
      1. Solution
        1. Recap: Nested and Local Classes
        2. Nested Functions: Overview
        3. Attempts at Simulating Nested Functions in C++
        4. A Somewhat Improved Solution
        5. A Complete Solution
        6. Summary
    3. 34. Preprocessor Macros
      1. Solution
        1. 1. Header Guards
        2. 2. Accessing Preprocessor Features
        3. 3. Selecting Code at Compile Time (or Build-Specific Code)
          1. a) Debug Code
          2. b) Platform-Specific Code
          3. c) Variant Data Representations
    4. 35. #Definition
      1. Solution
        1. Common Macro Pitfalls
          1. 1. Don't forget to put parentheses around arguments.
          2. 2. Don't forget to put parentheses around the whole expansion.
          3. 3. Watch for multiple argument evaluation.
          4. 4. Name tromping.
        2. Other Macro Drawbacks
          1. 5. Macros can't recurse.
          2. 6. Macros don't have addresses.
          3. 7. Macros are debugger-unfriendly.
        3. There Are Some Things Even a Macro Won't Do
  10. Miscellaneous Topics
    1. 36. Initialization
      1. Solution
    2. 37. Forward Declarations
      1. Solution
    3. 38. Typedef
      1. Solution
        1. Typedef: Controlling What's in a Name
          1. Typeability
          2. Readability
          3. Communication
          4. Portability
          5. Flexibility
          6. Traitability
        2. Summary
    4. 39. Namespaces, Part 1: Using-Declarations and Using-Directives
      1. Solution
        1. Using-Declarations
        2. Using-Directives
    5. 40. Namespaces, Part 2: Migrating to Namespaces
      1. Solution
        1. Migrating to Namespaces, Safely and Effectively
        2. Guidelines for a Good Long-Term Solution
          1. Namespace Rule #1: Never write using-directives in header files.
          2. Namespace Rule #2: Never write namespace using-declarations in header files.
          3. Namespace Rule #3: In implementation files, never write a using-declaration or a using-directive before an #include directive.
          4. “Kinda Sorta” Namespace Rule #4: Use C headers with the new style #include <cheader> instead of the old style #include <header.h>.
        3. Long-Term Approaches: A Motivating Example
        4. A Good Long-Term Solution
        5. A Not-So-Good Long-Term Solution
        6. An Effective Short-Term Solution
          1. Migration Step #1: In every header file, add “std::” qualifiers wherever needed.
          2. Migration Step #2: Create a new header file called myproject_last.h that contains the directive using namespace std;. In every implementation file, #include myproject_last.h after all other #includes.
        7. Conclusion: Migrating to the Long-Term Solution
  11. Afterword
  12. A. Optimizations That Aren't (in a Multithreaded World)
    1. Introduction
    2. What's the Fuss About?
    3. Recap: Plain Old Original:: String (Item 13)
    4. Using a Plain Old String: Single-Threaded
    5. Using a Plain Old String: Multithreaded
    6. Now Throw in an “Optimization”: Copy-On-Write (COW)
    7. Using a COW String: Multithreaded
    8. Mild versus Severe Inefficiencies
    9. Some Actual Numbers
    10. A Real-World Example: C++'s basic_string
    11. “Am I Affected?”
    12. Summary
  13. B. Test Results for Single-Threaded versus Multithread-Safe String Implementations
    1. Approach
    2. Raw Measurements
      1. Testing Const Copying and Destruction: The Target Case of Cow
      2. Testing Append(): An Always-Mutating Periodically-Reallocating Operation
      3. Testing Operator[](): A Possibly-Mutating Operation, Never Does Mutate
      4. Testing Various Integer Increment/Decrement Operations
    3. Test Harness
  14. Bibliography