Imperfect C++ Practical Solutions for Real-Life Programming

Book description

Imperfect C++

C++, although a marvelous language, isn't perfect. Matthew Wilson has been working with it for over a decade, and during that time he has found inherent limitations that require skillful workarounds. In this book, he doesn't just tell you what's wrong with C++, but offers practical techniques and tools for writing code that's more robust, flexible, efficient, and maintainable. He shows you how to tame C++'s complexity, cut through its vast array of paradigms, take back control over your code—and get far better results.

If you're a long-time C++ developer, this book will help you see your programming challenges in new ways—and illuminate powerful techniques you may never have tried. If you're newer to C++, you'll learn principles that will make you more effective in all of your projects. Along the way, you'll learn how to:

  • Overcome deficiencies in C++'s type system

  • Enforce software design through constraints, contracts, and assertions

  • Handle behavior ignored by the standard— including issues related to dynamic libraries, static objects, and threading

  • Achieve binary compatibility between dynamically loading components

  • Understand the costs and disadvantages of implicit conversions—and the alternatives

  • Increase compatibility with diverse compilers, libraries, and operating environments

  • Help your compiler detect more errors and work more effectively

  • Understand the aspects of style that impact reliability

  • Apply the Resource Acquisition Is Initialization mechanism to a wide variety of problem domains

  • Manage the sometimes arcane relationship between arrays and pointers

  • Use template programming to improve flexibility and robustness

  • Extend C++: including fast string concatenation, a true NULL-pointer, flexible memory buffers, Properties, multidimensional arrays, and Ranges

  • The CD-ROM contains a valuable variety of C++ compilers, libraries, test programs, tools, and utilities, as well as the author's related journal articles. New and updated imperfections, along with software libraries and example code are available online at http://imperfectcplusplus.com.

    © Copyright Pearson Education. All rights reserved.

    Table of contents

    1. Copyright
      1. Dedication
    2. Preface
      1. What You Will Learn
      2. What I Assume You Know
      3. Organization
      4. References
      5. Supplementary Material
        1. CD-ROM
        2. Online Resources
      6. Acknowledgments
    3. Prologue: Philosophy of the Imperfect Practitioner
      1. C++ Is Not Perfect
      2. Hairshirt Programming
      3. Making the Compiler Your Batman
      4. Never Say Die
      5. The Spirit of Imperfect C++
      6. Coding Style
      7. Terminology
        1. Fundamental Types and Compound Types
        2. Object Types
        3. Scalar Types and Class Types
        4. Aggregates
        5. POD Types
    4. Imperfections, Constraints, Definitions, and Recommendations
    5. One. Fundamentals
      1. 1. Enforcing Design: Constraints, Contracts, and Assertions
        1. 1.1. Eggs and Ham
        2. 1.2. Compile-Time Contracts: Constraints
          1. 1.2.1. must_have_base()
          2. 1.2.2. must_be_subscriptable()
          3. 1.2.3. must_be_subscriptable_as_decayable_pointer()
          4. 1.2.4. must_be_pod()
          5. 1.2.5. must_be_same_size()
          6. 1.2.6. Using Constraints
          7. 1.2.7. Constraints and TMP
          8. 1.2.8. Constraints: Coda
        3. 1.3. Runtime Contracts: Preconditions, Postconditions, and Invariants
          1. 1.3.1. Preconditions
          2. 1.3.2. Post-conditions
          3. 1.3.3. Class Invariants
          4. 1.3.4. Checking? Invariably!
          5. 1.3.5. To DbC, or Not to DbC?
          6. 1.3.6. Runtime Contracts: Coda
        4. 1.4. Assertions
          1. 1.4.1. Getting the Message
          2. 1.4.2. Inappropriate Assertions
          3. 1.4.3. Syntax and 64-Bit Pointers
          4. 1.4.4. Avoid verify()
          5. 1.4.5. Naming Your Assertions
          6. 1.4.6. Avoid #ifdef _DEBUG
          7. 1.4.7. DebugAssert() vs int 3
          8. 1.4.8. Static/Compile-Time Assertions
          9. 1.4.9. Assertions: Coda
      2. 2. Object Lifetime
        1. 2.1. The Object Life Cycle
          1. 2.1.1. In-Place Construction
        2. 2.2. Controlling Your Clients
          1. 2.2.1. Member Types
          2. 2.2.2. Default Constructor
          3. 2.2.3. Copy Constructor
          4. 2.2.4. Copy Assignment
          5. 2.2.5. new and delete
          6. 2.2.6. Virtual Delete
          7. 2.2.7. explicit
          8. 2.2.8. Destructor
          9. 2.2.9. friend
        3. 2.3. MILs and Boon
          1. 2.3.1. Getting a Bigger Playpen
          2. 2.3.2. Member-Ordering Dependencies
          3. 2.3.3. offsetof()
          4. 2.3.4. MIL: Coda
      3. 3. Resource Encapsulation
        1. 3.1. A Taxonomy of Resource Encapsulation
        2. 3.2. POD Types
          1. 3.2.1. Direct Manipulation
          2. 3.2.2. API Functions and Transparent Types
          3. 3.2.3. API Functions and Opaque Types
        3. 3.3. Wrapper Proxies
        4. 3.4. RRID Types
          1. 3.4.1. Default-Initialized: Lazy Initialization
          2. 3.4.2. Uninitialized
        5. 3.5. RAII Types
          1. 3.5.1. Immutable / Mutable
          2. 3.5.2. Internally/Externally Initialized
          3. 3.5.3. RAII Permutations
        6. 3.6. RAII Coda
          1. 3.6.1. Invariants
          2. 3.6.2. Error Handling
      4. 4. Data Encapsulation and Value Types
        1. 4.1. A Taxonomy of Data Encapsulation
        2. 4.2. Value Types and Entity Types
        3. 4.3. A Taxonomy of Value Types
        4. 4.4. Open Types
          1. 4.4.1. POD Open Types
          2. 4.4.2. C++ Data Structures
        5. 4.5. Encapsulated Types
        6. 4.6. Value Types
        7. 4.7. Arithmetic Value Types
        8. 4.8. Value Types Coda
        9. 4.9. Encapsulation Coda
      5. 5. Object Access Models
        1. 5.1. Vouched Lifetimes
          1. 5.1.1. Checkout Model
        2. 5.2. Copied for Caller
        3. 5.3. Given to Caller
        4. 5.4. Shared Objects
      6. 6. Scoping Classes
        1. 6.1. Value
        2. 6.2. State
        3. 6.3. APIs and Services
          1. 6.3.1. APIs
          2. 6.3.2. Services
        4. 6.4. Language Features
    6. Two. Surviving the Real World
      1. 7. ABI
        1. 7.1. Sharing Code
        2. 7.2. C ABI Requirements
          1. 7.2.1. Structure Layout
          2. 7.2.2. Calling Conventions, Symbol Names, and Object File Formats
          3. 7.2.3. Static Linking
          4. 7.2.4. Dynamic Linking
        3. 7.3. C++ ABI Requirements
          1. 7.3.1. Object Layout
          2. 7.3.2. Virtual Functions
          3. 7.3.3. Calling Conventions and Mangling
          4. 7.3.4. Static Linking
          5. 7.3.5. Dynamic Linking
        4. 7.4. I Can C Clearly Now
          1. 7.4.1. extern “C”
          2. 7.4.2. Namespaces
          3. 7.4.3. extern “C++”
          4. 7.4.4. Getting a Handle on C++ Classes
          5. 7.4.5. Implementation-defined Pitfalls
      2. 8. Objects Across Borders
        1. 8.1. Mostly Portable vtables?
          1. 8.1.1. vtable Layouts
          2. 8.1.2. Dynamic Manipulation of vtables
        2. 8.2. Portable vtables
          1. 8.2.1. Simplifying Macros
          2. 8.2.2. Compatible Compilers
          3. 8.2.3. Portable Server Objects
          4. 8.2.4. Simplifying the Implementation of Portable Interfaces
          5. 8.2.5. C Client Code
          6. 8.2.6. OAB Constraints
        3. 8.3. ABI/OAB Coda
      3. 9. Dynamic Libraries
        1. 9.1. Calling Functions Explicitly
          1. 9.1.1. Calling C++ Functions Explicitly
          2. 9.1.2. Breaking C++ Access Control
        2. 9.2. Indentity: Link Units and Link Space
          1. 9.2.1. Link Units
          2. 9.2.2. Link Space
          3. 9.2.3. Multiple Identities
        3. 9.3. Lifetime
        4. 9.4. Versioning
          1. 9.4.1. Lost Functions
          2. 9.4.2. Changed Signatures
          3. 9.4.3. Behavioral Changes
          4. 9.4.4. Constants
        5. 9.5. Resource Ownership
          1. 9.5.1. Shared Pools
          2. 9.5.2. Return to Callee
        6. 9.6. Dynamic Libraries: Coda
      4. 10. Threading
        1. 10.1. Synchronizing Integer Access
          1. 10.1.1. Operating System Functions
          2. 10.1.2. Atomic Types
        2. 10.2. Synchronizing Block Access: Critical Regions
          1. 10.2.1. Interprocess and Intraprocess Mutexes
          2. 10.2.2. Spin Mutexes
        3. 10.3. Atomic Integer Performance
          1. 10.3.1. Atomic Integer by Mutex
          2. 10.3.2. Run Time Architecture Dispatching
          3. 10.3.3. Performance Comparisons
          4. 10.3.4. Atomic Integer Operations Coda
        4. 10.4. Multithreading Extensions
          1. 10.4.1. synchronized
          2. 10.4.2. Anonymous synchronized
          3. 10.4.3. atomic
        5. 10.5. Thread Specific Storage
          1. 10.5.1. Re-entrancy
          2. 10.5.2. Thread-Specific Data / Thread-Local Storage
          3. 10.5.3. __declspec(thread) and TLS
          4. 10.5.4. The Tss Library
          5. 10.5.5. TSS Performance
      5. 11. Statics
        1. 11.1. Nonlocal Static Objects: Globals
          1. 11.1.1. Intracompilation Unit Ordering
          2. 11.1.2. Intercompilation Unit Ordering
          3. 11.1.3. Avoid Globals, in the main()
          4. 11.1.4. Global Objects Coda: Ordering
        2. 11.2. Singletons
          1. 11.2.1. Meyers Singleton
          2. 11.2.2. Alexandrescu Singleton
          3. 11.2.3. Just-in-Time Schwarz Counters: A Nifty Idea
          4. 11.2.4. Counting on APIs
          5. 11.2.5. Counted APIs, Wrappers, Proxies: Ordered Singletons at Last!
        3. 11.3. Function-Local Static Objects
          1. 11.3.1. Sacrifice Lazy Evaluation
          2. 11.3.2. Spin Mutexes to the Rescue
        4. 11.4. Static Members
          1. 11.4.1. Heading Off Linker Issues
          2. 11.4.2. Adaptive Code
        5. 11.5. Statics Coda
      6. 12. Optimization
        1. 12.1. Inline Functions
          1. 12.1.1. Beware Premature Optimization
          2. 12.1.2. Header-Only Libraries
        2. 12.2. Return Value Optimization
          1. 12.2.1. Named Return Value Optimization
        3. 12.3. Empty Base Optimization
        4. 12.4. Empty Derived Optimization
        5. 12.5. Preventing Optimization
    7. Three. Language Concerns
      1. 13. Fundamental Types
        1. 13.1. May I Have a byte?
          1. 13.1.1. Look for a Sign
          2. 13.1.2. It's All in the Name
          3. 13.1.3. Peering into the Void
          4. 13.1.4. Extra Safety
        2. 13.2. Fixed-Sized Integer Types
          1. 13.2.1. Platform Independence
          2. 13.2.2. Type-Specific Behavior
          3. 13.2.3. Fixed-Sized Integer Types: Coda
        3. 13.3. Large Integer Types
        4. 13.4. Dangerous Types
          1. 13.4.1. References and Temporaries
          2. 13.4.2. bool
      2. 14. Arrays and Pointers
        1. 14.1. Don't Repeat Yourself
        2. 14.2. Arrays Decay into Pointers
          1. 14.2.1. Subscript Operator Commutativity
          2. 14.2.2. Preventing Decay
        3. 14.3. dimensionof()
        4. 14.4. Cannot Pass Arrays to Functions
        5. 14.5. Arrays Are Always Passed by Address
        6. 14.6. Arrays of Inherited Types
          1. 14.6.1. Store Polymorphic Types by Pointer
          2. 14.6.2. Provide Nondefault Constructors
          3. 14.6.3. Hide Vector new and delete
          4. 14.6.4. Use std::vector
          5. 14.6.5. Ensure That Types Are the Same Size
        7. 14.7. Cannot Have Multidimensional Arrays
      3. 15. Values
        1. 15.1. NULL—The Keyword That Wasn't
        2. 15.2. Down to Zero
        3. 15.3. Bending the Truth
        4. 15.4. Literals
          1. 15.4.1. Integers
          2. 15.4.2. Suffixes
          3. 15.4.3. Strings
        5. 15.5. Constants
          1. 15.5.1. Simple Constants
          2. 15.5.2. Class-Type Constants
          3. 15.5.3. Member Constants
          4. 15.5.4. Class-Type Member Constants
      4. 16. Keywords
        1. 16.1. interface
          1. 16.1.1. pinterface
        2. 16.2. temporary
        3. 16.3. owner
        4. 16.4. explicit(_cast)
          1. 16.4.1. Use Explicit Accessor Methods
          2. 16.4.2. Emulate Explicit Casts
          3. 16.4.3. Use Attribute Shims
        5. 16.5. unique
        6. 16.6. final
        7. 16.7. Unsupported Keywords
          1. 16.7.1. typename
      5. 17. Syntax
        1. 17.1. Class Layout
        2. 17.2. Conditional Expressions
          1. 17.2.1. Make It Boolean
          2. 17.2.2. A Dangerous Assignment
        3. 17.3. for
          1. 17.3.1. Initializer Scope
          2. 17.3.2. Heterogeneous Initializer Types
        4. 17.4. Variable Notation
          1. 17.4.1. Hungarian Notation
          2. 17.4.2. Member Variables
      6. 18. Typedefs
        1. 18.1. Pointer Typedefs
        2. 18.2. What's in a Definition?
          1. 18.2.1. Conceptual Type Definitions
          2. 18.2.2. Contextual Type Definitions
        3. 18.3. Aliases
          1. 18.3.1. Erroneous Conceptual Type Interchange
          2. 18.3.2. No Overloading on Conceptual type
        4. 18.4. True Typedefs
        5. 18.5. The Good, the Bad, and the Ugly
          1. 18.5.1. Good typedefs
          2. 18.5.2. Bad Typedefs
          3. 18.5.3. Dubious Typedefs
    8. Four. Cognizant Conversions
      1. 19. Casts
        1. 19.1. Implicit Conversion
        2. 19.2. Casting in C++
        3. 19.3. The Case for C Casts
        4. 19.4. Casts on Steroids
        5. 19.5. explicit_cast
        6. 19.6. literal_cast
        7. 19.7. union_cast
        8. 19.8. comstl::interface_cast
          1. 19.8.1. interface_cast_addref
          2. 19.8.2. interface_cast_noaddref
          3. 19.8.3. interface_cast_test
          4. 19.8.4. Operator Implementations
          5. 19.8.5. Protecting the Reference Count
          6. 19.8.6. interface_cast_base
          7. 19.8.7. IID_traits
          8. 19.8.8. interface_cast Coda
        9. 19.9. boost::polymorphic_cast
        10. 19.10. Casts: Coda
      2. 20. Shims
        1. 20.1. Embracing Change and Enhancing Flexibility
        2. 20.2. Attribute Shims
        3. 20.3. Logical Shims
        4. 20.4. Control Shims
        5. 20.5. Conversion Shims
        6. 20.6. Composite Shim Concepts
          1. 20.6.1. Access Shims
          2. 20.6.2. Return Value Lifetime
          3. 20.6.3. Generalized Type Manipulation
          4. 20.6.4. Efficiency Concerns
        7. 20.7. Namespaces and Koenig Lookup
        8. 20.8. Why Not Traits?
        9. 20.9. Structural Conformance
          1. 20.9.1. Semantic Conformance
        10. 20.10. Breaking Up the Monolith
        11. 20.11. Shims: Coda
      3. 21. Veneers
        1. 21.1. Lightweight RAII
        2. 21.2. Binding Data and Operations
          1. 21.2.1. pod_veneer
          2. 21.2.2. Creating Log Messages
          3. 21.2.3. Reducing Waste
          4. 21.2.4. Type-safe Message Classes
        3. 21.3. Rubbing Up to Concepts
        4. 21.4. Veneers: Coda
      4. 22. Bolt-ins
        1. 22.1. Adding Functionality
        2. 22.2. Skin Selection
        3. 22.3. Nonvirtual Overriding
        4. 22.4. Leveraging Scope
        5. 22.5. Simulated Compile-Time Polymorphism: Reverse Bolt-ins
        6. 22.6. Parameterized Polymorphic Packaging
        7. 22.7. Bolt-ins: Coda
      5. 23. Template Constructors
        1. 23.1. Hidden Costs
        2. 23.2. Dangling References
        3. 23.3. Template Constructor Specialization
        4. 23.4. Argument Proxies
        5. 23.5. Argument Targeting
        6. 23.6. Template Constructors: Coda
    9. Five. Operators
      1. 24. operator bool()
        1. 24.1. operator int() const
        2. 24.2. operator void *() const
        3. 24.3. operator bool() const
        4. 24.4. operator !()—not!
        5. 24.5. operator boolean const *() const
        6. 24.6. operator int boolean::*() const
        7. 24.7. Operating in the Real World
        8. 24.8. operator!
      2. 25. Fast, Non-intrusive String Concatenation
        1. 25.1. fast_string_concatenator<>
          1. 25.1.1. Working with Custom String Classes
          2. 25.1.2. Tying the Concatenators Together
          3. 25.1.3. The Concatenator Class
          4. 25.1.4. Internal Implementation
        2. 25.2. Performance
        3. 25.3. Working with Other String Classes
          1. 25.3.1. Incorporation into Standard Libraries
          2. 25.3.2. Incorporation into Modifiable Extant Classes
          3. 25.3.3. Interoperation with Nonmodifiable Classes
        4. 25.4. Concatenation Seeding
        5. 25.5. Pathological Bracing
        6. 25.6. Standardization
      3. 26. What's Your Address?
        1. 26.1. Can't Get the Real Address
          1. 26.1.1. STL Containment
          2. 26.1.2. ATL Wrapper Classes and CAdapt
          3. 26.1.3. Getting the Real Address
        2. 26.2. What Actions Are Carried Out during Conversion?
        3. 26.3. What Do We Return?
        4. 26.4. What's Your Address: Coda
          1. 26.4.1. A Sensationalist Backflip!
      4. 27. Subscript Operators
        1. 27.1. Pointer Conversion versus Subscript Operators
          1. 27.1.1. Choose Implicit Conversion Operators
          2. 27.1.2. Choose Subscript Operators
        2. 27.2. Handling Errors
          1. 27.2.1. Subscript Operators versus Iterators
        3. 27.3. Return Value
      5. 28. Increment Operators
        1. 28.1. Missing Postfix Operators
        2. 28.2. Efficiency
          1. 28.2.1. Detecting Unused Postfix Operators
      6. 29. Arithmetic Types
        1. 29.1. Class Definition
        2. 29.2. Default Construction
        3. 29.3. Initialization (Value Construction)
        4. 29.4. Copy Construction
        5. 29.5. Assignment
        6. 29.6. Arithmetic Operators
        7. 29.7. Comparison Operators
        8. 29.8. Accessing the Value
        9. 29.9. sinteger64
        10. 29.10. Truncations, Promotions, and Tests
          1. 29.10.1. Truncations
          2. 29.10.2. Promotions
          3. 29.10.3. Tests
        11. 29.11. Arithmetic Types: Coda
      7. 30. Short-circuit!
    10. Six. Extending C++
      1. 31. Return Value Lifetime
        1. 31.1. A Taxonomy of Return Value Lifetime Gotchas
          1. 31.1.1. Local Variables
          2. 31.1.2. Local Statics
          3. 31.1.3. Postdestruction Pointers
        2. 31.2. Why Return-by-Reference?
        3. 31.3. Solution 1—integer_to_string<>
          1. 31.3.1. RVL
        4. 31.4. Solution 2—TSS
          1. 31.4.1. __declspec(thread)
          2. 31.4.2. Win32 TLS
          3. 31.4.3. Platform-Independent APIs
          4. 31.4.4. RVL
        5. 31.5. Solution 3—Extending RVL
          1. 31.5.1. Solving Intrathread RVL-LS?
          2. 31.5.2. RVL
        6. 31.6. Solution 4—Static Array Size Determination
          1. 31.6.1. RVL
        7. 31.7. Solution 5—Conversion Shims
          1. 31.7.1. RVL
        8. 31.8. Performance
        9. 31.9. RVL: The Big Win for Garbage Collection
        10. 31.10. Potential Applications
        11. 31.11. Return Value Lifetime: Coda
      2. 32. Memory
        1. 32.1. A Taxonomy of Memory
          1. 32.1.1. Stack and Static Memory
          2. 32.1.2. Stack Expansion
          3. 32.1.3. Heap Memory
        2. 32.2. The Best of Both Worlds
          1. 32.2.1. alloca()
          2. 32.2.2. VLAs
          3. 32.2.3. auto_buffer<>
          4. 32.2.4. Using the Template
          5. 32.2.5. EBO, Where Art Thou?
          6. 32.2.6. Performance
          7. 32.2.7. Heap vs. Stack vs. . . .
          8. 32.2.8. pod_vector<>
        3. 32.3. Allocators
          1. 32.3.1. Function Pointers
          2. 32.3.2. Allocator Interfaces
          3. 32.3.3. Per-library Initialization
          4. 32.3.4. Per-Call Specification
        4. 32.4. Memory: Coda
      3. 33. Multidimensional Arrays
        1. 33.1. Facilitating Subscript Syntax
        2. 33.2. Sized at Run Time
          1. 33.2.1. Variable Length Arrays
          2. 33.2.2. vector< ... vector<T> ... >
          3. 33.2.3. boost::multi_array
          4. 33.2.4. fixed_array_1/2/3/4d
        3. 33.3. Sized at Compile Time
          1. 33.3.1. boost::array
          2. 33.3.2. static_array_1/2/3/4d
        4. 33.4. Block Access
          1. 33.4.1. Using std::fill_n()
          2. 33.4.2. array_size Shim
        5. 33.5. Performance
          1. 33.5.1. Sized at Run Time
          2. 33.5.2. Sized at Compile Time
        6. 33.6. Multidimensional Arrays: Coda
      4. 34. Functors and Ranges
        1. 34.1. Syntactic Clutter
        2. 34.2. for_all() ?
          1. 34.2.1. arrays
          2. 34.2.2. Naming Concerns
        3. 34.3. Local Functors
          1. 34.3.1. Unrolled Loops
          2. 34.3.2. Custom Functors
          3. 34.3.3. Nested Functors
          4. 34.3.4. Legally Bland
          5. 34.3.5. Generalized Functors: Type Tunnelling
          6. 34.3.6. A Step too Far, Followed by a Sure Step Beyond
          7. 34.3.7. Local Functors and Callback APIs
        4. 34.4. Ranges
          1. 34.4.1. The Range Concept
          2. 34.4.2. Notional Range
          3. 34.4.3. Iterable Range
          4. 34.4.4. Range Algorithms and Tags
          5. 34.4.5. Filters
          6. 34.4.6. Hypocrisy?
        5. 34.5. Functors and Ranges: Coda
      5. 35. Properties
        1. 35.1. Compiler Extensions
        2. 35.2. Implementation Options
          1. 35.2.1. A Taxonomy of Property Implementation Options
          2. 35.2.2. EMO?
        3. 35.3. Field Properties
          1. 35.3.1. field_property_get
          2. 35.3.2. field_property_set
          3. 35.3.3. Internal Fields Properties: Coda
          4. 35.3.4. field_property_get_external
          5. 35.3.5. field_property_set_external
          6. 35.3.6. Hacking Away
        4. 35.4. Method Properties
          1. 35.4.1. method_property_get
          2. 35.4.2. method_property_set
          3. 35.4.3. method_property_getset
          4. 35.4.4. Loop the Loop!
          5. 35.4.5. method_property_get_external
          6. 35.4.6. method_property_set_external
          7. 35.4.7. method_property_getset_external
        5. 35.5. Static Properties
          1. 35.5.1. Static Field Properties
          2. 35.5.2. Internal Static Method Properties
          3. 35.5.3. External Static Method Properties
        6. 35.6. Virtual Properties
        7. 35.7. Property Uses
          1. 35.7.1. Genericity
          2. 35.7.2. Type Substitution for Diagnostics
        8. 35.8. Properties: Coda
    11. A. Compilers and Libraries
      1. A.1. Compilers
        1. A.1.1. Compiler Optimizations
      2. A.2. Libraries
        1. A.2.1. Boost
        2. A.2.2. STLSoft
        3. A.2.3. Others
      3. A.3. Other Resources
        1. A.3.1. Journals
        2. A.3.2. Other Languages
        3. A.3.3. Newsgroups
    12. B. “Watch That Hubris!”
      1. B.1. Operator Overload
      2. B.2. DRY Rued Yesterday
      3. B.3. Paranoid Programming
      4. B.4. To Insanity, and Beyond!
    13. C. Arturius
    14. D. The CD
    15. Epilogue
    16. Bibliography

    Product information

    • Title: Imperfect C++ Practical Solutions for Real-Life Programming
    • Author(s): Matthew Wilson
    • Release date: October 2004
    • Publisher(s): Addison-Wesley Professional
    • ISBN: 9780321228772