C++ / a working model

BOOK / SOURCE & READING RECORD

The Design and Evolution of C++

Bjarne Stroustrup

1994 work, official publisher sample; 2002 China Machine Press English reprint ISBN 7-111-09592-8, 466-page scan incorporating later-printing corrections including 1995 explicit constructors

READING EVIDENCE / Full text read

The Design and Evolution of C++

The substantial main text of all 18 chapters has actually been read: Chapter 1 is taken from the publisher's English sample printed pages 19–25; Chapters 2–18 are taken from the 2002 English reprint scan, covering PDF pages 38–431 continuously page by page (including subsection pages; blank pages omitted from the scan are not counted as main text). Remote OCR text and code were read paragraph by paragraph; incompletely recognized code, tables, and inheritance/RTTI diagrams were verified against the original images; the final section PDF 387–431 was read directly from the images. 'full' means the 18 chapters of main text are complete, without claiming word-by-word proofreading or having read the bibliography and index at the end of the book. This reprint incorporates subsequent corrections including those from 1995 and does not pretend to be the unrevised 1994 first printing; the Chinese translation is not counted in the coverage.

Edition, actual reading range, and original sources →

Sources

List engineering constraints first, then choose language mechanisms

Chapter 1 §§1.1–1.3, printed pp.19–25; publisher sample PDF pp.30–36

The key of Chapter 1 is not to declare one language the winner, but to put an understandable model, acceptable runtime cost, separate compilation, and cross-environment implementation simultaneously into the design problem. A tool that can clearly express concepts is still unsuitable if it cannot complete actual computations; a tool that runs fast but lets type errors lurk for a long time also incurs a maintenance cost. The approach transferred to today is to first write down the invariants that domain objects must maintain, then decide whether inheritance, dynamic allocation, or templates are needed. Even a value type with only two integers can carry a real abstraction: it makes valid states more reliable than the caller's self-discipline. The author's performance observations of specific implementations at the time are historical evidence, not a permanent ranking of modern languages or compilers.

Zero overhead does not mean every abstraction is free

Chapter 4 §§4.2–4.6, printed pp.110–122; English scan PDF pp.121–133

The zero-overhead rule in Chapter 4 targets a cost that is easily overlooked: imposing an extra burden on every object and every access in order to support a few advanced features. It does not promise that any program will automatically become faster once abstractions are used, nor does it deny that implementations may make trade-offs for other goals. The book simultaneously requires that features can be implemented, can be taught to users, and can be combined with independently developed components; pushing any single principle to an extreme would instead lose balance. Applied to code review, one should separately ask whether unused features are paid for, what work the actual usage path does, and whether necessary control is retained, rather than judging efficiency by the length of the syntax. Language standards usually specify behavior and do not promise a fixed layout or machine instructions; costs still need to be measured in the target environment.

Portability comes from clear boundaries, not from luckily compiling

Chapter 6 §§6.1–6.1.1, pp.133–135; §6.3.2, pp.143–146; scan PDF pp.143–145,153–156

Chapter 6 regards the standard as a contract between programmers and implementers, while pointing out that the contract does not take care of object layout, debug formats, or the entire operating-system environment. The discussion of temporary-object lifetimes further shows that leaving rules vague does not give users real freedom: after different implementations make different choices, portable programs can only rely on the most stringent intersection. The same applies to designing interfaces today: the lifetimes of owned objects and borrowed objects must be stated clearly; a pointer passing type checking does not mean the storage it points to is still valid. The book's descriptions of remainder of negative numbers, implicit int, and trigraphs are historical rules and cannot serve as the C++20 specification; what is worth retaining is the way of thinking that distinguishes guarantees, implementation differences, and interface preconditions.

Design composable libraries first, then debate language features

Chapter 8 §§8.1–8.2.3, pp.181–184, §8.5 p.194; Chapter 9 §9.2.3 p.200; scan PDF pp.190–193,203,209

Chapter 8 places whether independently developed libraries can work together at the center of design: name conflicts, error propagation, resource management, and type information can all prevent two separately correct components from being assembled. Adding one more language feature does not equal solving all integration problems; two foundational class libraries that both claim to cover the whole world are especially prone to squeezing each other. Actual design should first clarify constraints such as recompilation cost, ways for users to extend, and whether there are cross-language calls, then decide to use value types, templates, or abstract interfaces. Chapter 9 reflects on the shortcomings of early foundational libraries, showing that reinventing the wheel also pushes beginners too early toward complex implementation details. Modern teaching should first learn to use standard containers and resource-management types, then study implementations; this does not prevent going deeper into the lower layers when needed.

Error notification and resource cleanup are two different responsibilities

Chapter 16 §§16.4–16.5, printed pp.386–390, §§16.9–16.9.1 pp.395–397; scan PDF pp.392–396,401–403

Chapter 16 separates the library discovering failure from the upper layer deciding how to handle failure, showing that the meaning of exceptions is not to automatically repair errors for the program, but to allow information to cross layers that temporarily cannot handle it. Cleaning up resources relies on another contract: resources are owned by objects, and cleanup is performed when a constructed object leaves its scope. Pairing every allocation with a handwritten catch and then releasing looks cautious, but it intertwines the normal path with cleanup logic and easily misses a second failure point. Modern code can take up this idea with standard RAII types, but old throw-type lists, unexpected, or historical bad-allocation names cannot be treated as the C++20 interface. The table-driven scheme designed in the book for non-throwing paths is an implementation strategy and does not equal that all exception handling has no time or space cost in any environment.

Explain the work it undertakes before replacing the mechanism

Chapter 18 §18.1, printed pp.423–426; English reprint scan PDF pp.428–431

Chapter 18 does not stop at the slogan that macros are unsafe, but breaks down the tasks undertaken by the preprocessor: symbolic constants, type generalization, source-file composition, conditional selection, and implementation control are not the same problem. Some tasks can be handed to scoped, typed language mechanisms; others cannot be replaced by ordinary ifs alone, because unexecuted branches still need to pass syntax and type checking. When migrating old code, first recognize the specific problem the macro solves, then choose a substitute; this is more reliable than announcing a ban all at once. The include keyword envisioned in the book was not an accepted feature at the time; today's constexpr, if constexpr, and modules each have their own applicable boundaries, and later-appearing mechanisms cannot be written back as 1994 facts.

Related fundamentals

Encapsulation, Inheritance, and Composition: The Boundaries of OOPAccess Control and Inheritance Privilegesexplicit: Leave Conversion Intent at the Call SiteFrom Source Files to a Program: Compilation and Linking

Original practice →