Table of Contents
About the Author
About the Technical Reviewer
Acknowledgments
Chapter 1: Introduction
Software Entropy
Why C++?
Clean Code
C++11: The Beginning of a New Era
Who This Book Is For
Conventions Used in This Book
Sidebars
Notes, Tips, and Warnings
Code Samples
Coding Style
C++ Core Guidelines
Companion Website and Source Code Repository
UML Diagrams
Chapter 2: Build a Safety Net
The Need for Testing
Introduction to Testing
Unit Tests
What About QA?
Rules for Good Unit Tests
Test Code Quality
Unit Test Naming
Unit Test Independence
One Assertion per Test
Independent Initialization of Unit Test Environments
Exclude Getters and Setters
Exclude Third-Party Code
Exclude External Systems
What Do We Do with the Database?
Don’t Mix Test Code with Production Code
Tests Must Run Fast
How Do You Find a Test’s Input Data?
Equivalence Partitioning
Boundary Value Analysis
Test Doubles (Fake Objects)
Chapter 3: Be Principled
What Is a Principle?
KISS
YAGNI
DRY
It’s About Knowledge!
Building Abstractions Is Sometimes Hard
Information Hiding
Strong Cohesion
Loose Coupling
Be Careful with Optimizations
Principle of Least Astonishment (PLA)
The Boy Scout Rule
Collective Code Ownership
Chapter 4: Basics of Clean C++
Good Names
Names Should Be Self-Explanatory
Use Names from the Domain
Choose Names at an Appropriate Level of Abstraction
Avoid Redundancy When Choosing a Name
Avoid Cryptic Abbreviations
Avoid Hungarian Notation and Prefixes
Avoid Using the Same Name for Different Purposes
Comments
Let the Code Tell the Story
Do Not Comment Obvious Things
Don’t Disable Code with Comments
Don’t Write Block Comments
Don’t Use Comments to Substitute Version Control
The Rare Cases Where Comments Are Useful
Documentation Generation from Source Code
Functions
One Thing, No More!
Let Them Be Small
“But the Call Time Overhead!”
Function Naming
Use Intention-Revealing Names
Parameters and Return Values
Number of Parameters
Avoid Flag Parameters
Avoid Output Parameters
Don’t Pass or Return 0 (NULL, nullptr)
Strategies for Avoiding Regular Pointers
Choose simple object construction on the stack instead of on the heap
In a function’s argument list, use (const) references instead of pointers
If it is inevitable to deal with a pointer to a resource, use a smart one
If an API returns a raw pointer...
The Power of const Correctness
About Old C-Style in C++ Projects
Choose C++ Strings and Streams over Old C-Style char*
Avoid Using printf(), sprintf(), gets(), etc.
Choose Standard Library Containers over Simple C-Style Arrays
Use C++ Casts Instead of Old C-Style Casts
Avoid Macros
Chapter 5: Advanced Concepts of Modern C++
Managing Resources
Resource Acquisition Is Initialization (RAII)
Smart Pointers
Unique Ownership with std::unique_ptr
Shared Ownership with std::shared_ptr
No Ownership, but Secure Access with std::weak_ptr
Atomic Smart Pointers
Avoid Explicit New and Delete
Managing Proprietary Resources
We Like to Move It
What Are Move Semantics?
The Matter with Those lvalues and rvalues
rvalue References
Don’t Enforce Move Everywhere
The Rule of Zero
The Compiler Is Your Colleague
Automatic Type Deduction
Computations During Compile Time
Variable Templates
Don’t Allow Undefined Behavior
Type-Rich Programming
Know Your Libraries
Take Advantage of
Easier Parallelization of Algorithms Since C++17
Sorting and Output of a Container
More Convenience with Ranges
Non-Owning Ranges with Views
Comparing Two Sequences
Take Advantage of Boost
More Libraries That You Should Know About
Proper Exception and Error Handling
Prevention Is Better Than Aftercare
No Exception Safety
Basic Exception Safety
Strong Exception Safety
The No-Throw Guarantee
An Exception Is an Exception, Literally!
If You Can’t Recover, Get Out Quickly
Define User-Specific Exception Types
Throw by Value, Catch by const Reference
Pay Attention to the Correct Order of Catch Clauses
Interface Design
Attributes
noreturn (since C++11)
deprecated (since C++14)
nodiscard (since C++17)
maybe_unused (since C++17)
Concepts: Requirements for Template Arguments
Specifying a Concept
Applying a Concept
Chapter 6: Modularization
The Basics of Modularization
Criteria for Finding Modules
Focus on the Domain of Your Software
Abstraction
Choose a Hierarchical Decomposition
Single Responsibility Principle (SRP)
Single Level of Abstraction (SLA)
The Whole Enchilada
Object-Orientation
Object-Oriented Thinking
Principles for Good Class Design
Keep Classes Small
Open-Closed Principle (OCP)
A Short Comparison of Type Erasure Techniques
Liskov Substitution Principle (LSP)
The Square-Rectangle Dilemma
Favor Composition over Inheritance
Interface Segregation Principle (ISP)
Acyclic Dependency Principle
Dependency Inversion Principle (DIP)
Don’t Talk to Strangers (The Law of Demeter)
Avoid Anemic Classes
Tell, Don’t Ask!
Avoid Static Class Members
Modules
The Drawbacks of #include
Modules to the Rescue
Under the Hood
Three Options for Using Modules
Include Translation
Header Importation
Module Importation
Separating Interface and Implementation
The Impact of Modules
Chapter 7: Functional Programming
What Is Functional Programming?
What Is a Function?
Pure vs Impure Functions
Functional Programming in Modern C++
Functional Programming with C++ Templates
Function-Like Objects (Functors)
Generator
Unary Function
Predicate
Binary Functors
Binders and Function Wrappers
Lambda Expressions
Generic Lambda Expressions (C++14)
Lambda Templates (C++20)
Higher-Order Functions
Map, Filter, and Reduce
Map
Filter
Reduce (Fold)
Fold Expressions in C++17
Pipelining with Range Adaptors (C++20)
Clean Code in Functional Programming
Chapter 8: Test-Driven Development
The Drawbacks of Plain Old Unit Testing (POUT)
Test-Driven Development as a Game Changer
The Workflow of TDD
TDD by Example: The Roman Numerals Code Kata
Preparations
The First Test
The Second Test
The Third Test and the Tidying Afterward
More Sophisticated Tests with a Custom Assertion
It’s Time to Clean Up Again
Approaching the Finish Line
Done!
The Advantages of TDD
When We Should Not Use TDD
TDD Is Not a Replacement for Code Reviews
Chapter 9: Design Patterns and Idioms
Design Principles vs Design Patterns
Some Patterns and When to Use Them
Dependency Injection (DI)
The Singleton Anti-Pattern
Dependency Injection to the Rescue
Adapter
Strategy
Command
Command Processor
Composite
Observer
Factories
Simple Factory
Facade
The Money Class
Special Case Object (Null Object)
What Is an Idiom?
Some Useful C++ Idioms
The Power of Immutability
Substitution Failure Is Not an Error (SFINAE)
The Copy-and-Swap Idiom
Pointer to Implementation (PIMPL)
Appendix A:
Small UML Guide
Structural Modeling
Component
Class and Object
Interface
Association
Generalization
Dependency
Template and Template Binding
Behavioral Modeling
Activity Diagram
Action
Control Flow Edge
Other Activity Nodes
Sequence Diagram
Lifeline
Message
State Diagram
State
Transitions
External Transitions
Internal Transitions
Trigger
Stereotypes
Bibliography
Index