C++ / a working model

THE FIELD GUIDE / 163 LESSONS

One question, finished properly.

Read the claim, then the mechanism. Run the program. Answer the exercise yourself.

163 lessons · progress stays in this browser

Start with the first lesson →
01

Language fundamentals / C++11

sizeof: Measure Object Representation, Not Runtime Content

sizeof queries the object-representation size of a static type, in C++ bytes, including necessary padding. It often looks like a function call but is an operator whose operand is not evaluated; results for arrays, references, and pointers must be understood separately.

7 min
02

Language fundamentals / C++11

sizeof and strlen: Capacity, Terminator, and Logical Length

sizeof measures type occupancy; strlen walks a character sequence looking for the first zero character. They answer different questions. A string literal includes a terminating zero; an embedded zero ends strlen early. A pointer itself records no capacity and does not guarantee that it points to a valid string.

7 min
03

Language fundamentals / C++11

Array Parameter Decay: Declaration Adjustment and Array-to-Pointer Conversion

An array is not a pointer, but a function parameter written in array form is adjusted to a pointer type, and in ordinary calls an array argument is often converted to a pointer to its first element. Bounds do not follow automatically; to keep length, use an array reference, a container, or C++20's span.

8 min
04

Language fundamentals / C++11

const: Read-Only Access Paths and Constant Objects

const restricts modification through a given type, but a read-only reference does not mean the underlying object never changes. Understanding top-level versus low-level const, the read-only promise of member functions, and the difference between const and constexpr is what lets you write interfaces that are reliable without over-promising.

8 min
05

Language fundamentals / C++11

static: three contexts of storage duration, linkage, and class members

The meaning of static depends on where it appears: a local variable obtains static storage duration, a namespace-scope entity can obtain internal linkage, and a class static member does not belong to any one instance. Thread-safe initialization of a local static does not mean later reads and writes are automatically thread-safe.

8 min
06

Language fundamentals / C++11

volatile: observable access, not thread synchronization

volatile tells the implementation that the related accesses have observable effects and must not be discarded as ordinary memory accesses. It does not provide atomicity, inter-thread ordering, or happens-before, and it does not promise to bypass CPU caches; thread communication should use atomic operations or locks.

8 min
07

Language fundamentals / C++11

Alignment: memory alignment and struct padding

Alignment states the address conditions under which an object may be placed, and sizeof includes the padding required for a valid layout. alignof queries a type's requirement, and alignas raises the alignment requirement of a declaration. Adding member sizes cannot replace layout calculation, and a packed struct cannot replace portable serialization.

8 min
08

Language fundamentals / C++11

Endianness: separating numeric value from byte order

Endianness describes how the bytes of a multi-byte scalar are arranged in storage; it does not change the numeric value itself. A portable protocol should define field widths and encoding order explicitly, then encode and decode with unsigned arithmetic. Do not guess endianness by unaligned casts or by reading an inactive union member.

8 min
09

Language fundamentals / C++11

class and struct: Different Default Access, Same Capabilities

In C++, both class and struct define class types, and both support constructors, destructors, inheritance, virtual functions, and templates. The language difference is mainly default member access and default inheritance access. Using struct for simple data and class to maintain invariants is a design convention, not a capability limit.

7 min
10

Language fundamentals / C++11

Macros and inline: Text Substitution Is Not a Function Call

Function-like macros replace tokens during preprocessing and do not provide parameter types, ordinary scope, or a single-evaluation guarantee. An inline function has full function semantics; the specifier mainly concerns definition rules across translation units and does not force machine-code inlining. For constants and computation, prefer constexpr or templates.

8 min
11

Language fundamentals / C++11

typedef and using: A Type Alias Is Not a New Type

Both typedef and using give a name to an existing type; they do not create an independent type and they are not macro substitution. The using syntax is a better fit for complex types and alias templates. Adding const to a pointer alias constrains the whole pointer type; it does not automatically constrain the object it points to.

7 min
12

Language fundamentals / C++11

explicit: Leave Conversion Intent at the Call Site

explicit stops a constructor or conversion function from participating in some implicit conversions, but still allows direct initialization and explicit conversion. It is suitable for protecting units, capacities, and resource wrapper types. explicit operator bool can also support contextual conversion to bool while avoiding accidental numeric conversion.

8 min
13

Language fundamentals / C++11

extern: Declare Shared Entities Instead of Duplicating Allocation

extern is commonly used to declare a variable defined elsewhere so multiple translation units refer to the same entity. Distinguish declaration from definition, and scope from linkage; an extern variable declaration with an initializer is usually a definition, and include guards will not eliminate duplicate definitions that appear in a header.

8 min
14

Language fundamentals / C++11

extern "C": Language Linkage and the C ABI Boundary

extern "C" specifies C language linkage for applicable function and variable declarations so they can connect to a compatible C interface. It does not switch the function body to the C language, and it does not give arbitrary C++ types a cross-language ABI; names, calling convention, layout, and resource responsibility must each be handled separately.

9 min
15

Language fundamentals / C++11

mutable: Mutable Implementation State in a Logically Read-Only Object

mutable allows specific non-static data members to be modified even when the containing object is const, which is appropriate for caches, mutexes, and similar implementation details. It does not automatically provide synchronization, and it should not conceal changes to logical state; mutable on a lambda instead controls whether a by-value capture copy can be modified.

8 min
16

Language fundamentals / C++11

The Four Casts: Conversion Intent and Safety Preconditions

static_cast, dynamic_cast, const_cast, and reinterpret_cast each express a different conversion intent, but the keywords themselves do not guarantee runtime safety. Before choosing one, first establish numeric range, dynamic type, actual mutability, and the object's lifetime, alignment, and type-access rules.

10 min
17

The object model / C++11

Encapsulation, Inheritance, and Composition: The Boundaries of OOP

Encapsulation maintains an object's invariants. Public inheritance expresses a substitutable interface relationship; composition expresses ownership or use. Do not build an inheritance hierarchy just because you can reuse a few lines of code. First define legal states and the call contract, then decide whether you need runtime polymorphism.

8 min
18

The object model / C++11

Access Control and Inheritance Privileges

public, protected, and private control the accessibility of names; the inheritance specifier also controls whether the base-class interface and upcasts are available to outsiders. Access checking does not filter overload candidates for you, and protected does not let a derived class access protected members through an arbitrary base-class object.

8 min
19

The object model / C++11

Overload, Override, and Hiding: Overload / Override / Hiding

Overload selects a signature from candidate functions at compile time; override decides which implementation a virtual call ultimately executes; hiding happens at the name-lookup stage. All three can appear at once. Use override to check override intent, and use using to restore the needed set of base-class overloads.

9 min
20

The object model / C++11

Construction and destruction order

The most-derived class initializes virtual bases first, then initializes direct bases and members in declaration order, and finally runs the constructor body. The written order of the initializer list cannot change these rules; destruction cleans up completed subobjects in reverse, and construction failure also relies on this determinate order.

10 min
21

The object model / C++11

Destructors, exceptions, and noexcept

Destruction is for reliable cleanup, not for business commits that must report failure. Destructors are usually implicitly non-throwing; an exception that crosses a noexcept boundary terminates the program, and even when throwing is allowed, another exception escaping a destructor during stack unwinding also calls terminate.

8 min
22

The object model / C++11

Deep copy, shallow copy, and the Rule of Zero / Five

Default copy proceeds memberwise; whether underlying resources are shared depends on the member types, not on a single deep-copy or shallow-copy label. Prefer letting standard resource types manage ownership; only when custom copy semantics are truly required should copy, move, assignment, and destruction be designed together.

10 min
23

The object model / C++11

Static and Dynamic Polymorphism, Slicing, and RTTI

Templates compose calls from compile-time types; virtual functions let one base interface choose an implementation at run time. Copying by value into a base object slices away the derived part. RTTI can query a live polymorphic object safely, but it cannot repair a dangling pointer or replace a sound interface design.

9 min
24

The object model / C++11

this, Object Qualification, and Chained Interfaces

this is the pointer expression through which an implicit-object member function operates on an object; the type it points to changes with the member function's const qualification. Returning *this can build a chained interface, but it does not extend the object's lifetime. A static member function has no this, and capturing this does not mean owning the object.

8 min
25

The object model / C++11

Vtables: Language Semantics and ABI Implementation

The standard specifies which final overrider a virtual call should select, but it does not specify the number of vtables, the location of a vptr, or the object's memory map. Common ABIs implement those semantics with vtables, adjustment thunks, and RTTI metadata. Understanding them helps debugging, but you must not verify them with unguaranteed memory reads.

9 min
26

The object model / C++11

Abstract class and pure virtual function definitions

An abstract class cannot create a complete object, but it can have state, constructors, and ordinary implementations. Pure virtual means a concrete derived class must provide a non-pure final overrider; it does not mean the function cannot have a definition. A pure virtual destructor still needs an available definition when a derived object is actually destroyed.

8 min
27

The object model / C++14

Why there is no virtual constructor: factory and clone

A constructor cannot be declared virtual. A creation expression already decides the concrete type to build; an unfinished object cannot reverse-select the constructed type. Runtime type selection should use a factory; copying according to an existing dynamic type uses a virtual clone. Virtual calls during construction also have phase restrictions.

9 min
28

The object model / C++14

Base destructor: public virtual or protected nonvirtual

If a derived object may be owned and deleted through a base pointer, the base should provide a public virtual destructor. If the base is only an interface view that cannot be destroyed independently, a protected nonvirtual destructor can block that deletion. The choice follows the destruction contract, not a blanket rule of adding virtual whenever inheritance appears.

9 min
29

The object model / C++11

Why Member Templates Cannot Be virtual

Member function templates cannot be declared virtual, and a specialization of one will not automatically override a base-class virtual function. Ordinary non-template members of a class template may nevertheless be virtual. When both a generic entry point and run-time extension are required, the template conversion layer can be separated from a virtual interface of fixed signature.

8 min
30

The object model / C++20

Empty Classes, EBO and [[no_unique_address]]

A complete object of an empty class still has non-zero size, to support object identity and array addressing; an empty base-class subobject may occupy no extra space. C++20’s no_unique_address extends the opportunity for overlapping layout to members, but does not guarantee a particular sizeof, nor does it cancel the identity rules for objects of the same type.

8 min
31

Memory & ownership / C++20

Memory model and object lifetime

Available storage at an address is not the same as an accessible object already existing there. To decide whether an access is valid, check size, alignment, object lifetime, access type, and bounds together. Construction and destruction determine the object's phase; allocation and deallocation determine the underlying storage's phase.

10 min
32

Memory & ownership / C++11

Pointers: addresses, bounds, and borrowing

A pointer is a typed value that may point to an object, a function, or a past-the-end position, or it may be null or invalid. Non-null is not proof that you may dereference. Correct use depends on the object still being alive, matching types, and access staying in bounds. A raw pointer itself also does not express deallocation responsibility.

8 min
33

Memory & ownership / C++11

Reading pointer declarations

Read a complex declaration from the name outward, layer by layer according to how parentheses bind with the declarator. A pointer to an array, an array of pointers, and a function pointer are not equivalent. Which layer const qualifies also decides whether you can change the pointer or the target. Type aliases can make interfaces clearer.

9 min
34

Memory & ownership / C++14

Storage duration is not a memory partition

C++ specifies four storage durations—automatic, static, thread, and dynamic—and does not require a fixed stack, heap, or executable-file layout. The scope of a variable name, the linkage of a name, the lifetime of an object, and operating-system mappings answer different questions. They must not be mashed into a single address diagram.

9 min
35

Memory & ownership / C++11

References and temporary object lifetime

A reference provides an alias for an existing object. It is not an ordinary pointer that can be rebound, and it does not automatically own its target. A const reference can extend a temporary object's lifetime in specific initialization situations, but that extension does not travel arbitrarily along a parameter, a return value, or another reference.

9 min
36

Memory & ownership / C++14

Parameter passing and ownership contracts

When choosing a parameter type, first decide whether the function only reads, needs to modify, or takes ownership, then compare copy cost. Pass small values by value, large read-only objects by const reference, nullable borrows by pointer, and exclusive ownership by passing unique_ptr by value. These types communicate different contracts.

9 min
37

Memory & ownership / C++14

RAII: Give Cleanup Responsibility to Objects

RAII encapsulates resource acquisition and release inside owning objects, using a determined destructor timing to handle both normal returns and exception unwinding. The key is not that “resources must live on the stack,” but that every resource has a clear owner: construction failure does not leak, and destructors do not throw failures further outward.

10 min
38

Memory & ownership / C++14

Smart Pointers: Choosing an Ownership Vocabulary

Prefer direct value members and containers first. When a dynamic lifetime is truly needed, default to unique_ptr for exclusive ownership, and use shared_ptr only when multiple participants must all extend the lifetime. Observers use references, raw pointers, or weak_ptr; do not upgrade every access into ownership.

9 min
39

Memory & ownership / C++11

shared_ptr: Control Blocks and Thread-Safety Boundaries

What shared_ptr shares is a set of destruction responsibilities, usually recorded in a control block with owner counts, a deleter, and related information. The control block lets different shared_ptr instances concurrently manage the same object, but it does not protect the object’s internal data, and it does not allow unsynchronized modification of the same shared_ptr variable.

11 min
40

Memory & ownership / C++11

weak_ptr: Breaking Cycles and Safely Taking Temporary Ownership

weak_ptr observes an existing shared_ptr ownership group without increasing the strong-reference count, which suits back-pointers, subscribers, and non-owning caches. Always lock before access; the shared_ptr obtained on success protects the object's lifetime for that use. An expired check itself does not reserve the object.

10 min
41

Memory & ownership / C++11

malloc and the Allocator's Responsibilities

malloc provides uninitialized storage, returns a null pointer on failure, and must be paired with free; it does not run C++ constructors. An allocator may cache, bin, or request mappings from the system. Concrete implementations are not language guarantees. Requesting bytes and constructing objects should be understood as separate layers.

11 min
42

Memory & ownership / C++11

new/delete Expressions and Allocation Functions

A new expression usually obtains storage and initializes an object; a delete expression usually destroys the object and releases storage. operator new / operator delete are the underlying allocation functions inside those expressions, not equivalents of the full expressions. Understanding that layering is what lets you handle exceptions, arrays, and in-place construction correctly.

11 min
43

Memory & ownership / C++14

Memory leaks: from responsibility to evidence

A leak is first a resource that was not reclaimed at the agreed time, not a simple observation of whether process memory dropped. Cover exception paths with RAII, then combine LeakSanitizer allocation stacks with a repeatable workload to distinguish orphaned allocations, reference cycles, unbounded caches, and allocator retention.

10 min
44

Memory & ownership / C++11

Dangling and uninitialized pointers

An uninitialized pointer has no reliable pointer value; a dangling pointer once pointed at a valid object, but the target has already been destroyed or invalidated. Initializing to nullptr only fixes the starting state and cannot track object lifetime; the fundamental approach is to constrain borrow scope and arrange ownership correctly.

9 min
45

Memory & ownership / C++11

Memory safety diagnostics

Split memory errors into spatial out-of-bounds, temporal invalidation, missing initialization, deallocation-protocol errors, and concurrency races, then choose matching evidence. The crash site is often only the consequence; trace the first illegal access and the allocation and free stacks, and fix the root cause with explicit bounds and owning interfaces.

11 min
46

Modern C++ / C++11

Express null pointers with nullptr

nullptr is a null-pointer literal with its own type; it is neither integer zero nor some universal pointer. It keeps null-pointer semantics in overload resolution and template argument passing, but it does not make dereferencing safe and cannot replace object lifetime management.

7 min
47

Modern C++ / C++14

The deduction boundaries of auto and decltype(auto)

auto lets the compiler deduce a static type; it does not introduce a dynamic type. Whether references and const are kept depends on the declaration form; decltype(auto) applies decltype rules directly, and parentheses can change the result, especially for function return values and lifetime.

9 min
48

Modern C++ / C++11

Value categories and std::move: conversion is not a move

Lvalues, xvalues, and prvalues describe expressions, not permanent labels that variables own. std::move only converts an expression into a form that can participate in move overloads; whether resources actually transfer and what state the source is left in depend on the called type's contract.

9 min
49

Modern C++ / C++11

Forwarding references and perfect forwarding

A forwarding reference, together with template deduction, records the value category the caller passed in; std::forward then uses that information for the next call. It is for transparent wrappers, not an alias for every T&&, and not a more advanced general replacement for std::move.

10 min
50

Modern C++ / C++14

Lambda capture: a closure is an object with a lifetime

A lambda creates a closure object with a call operator; capture decides whether it stores a value or borrows outer state. Capture by value, by reference, and init-capture have different ownership consequences. Before storing a callback, prove that the objects it depends on live until the call finishes.

9 min
51

Modern C++ / C++11

Template deduction: match parameters first, then instantiate code

A template is a family of declarations and implementations generated from parameters, not a way to force every argument into one type. Understanding deduction by value versus by reference, non-type parameters, and definition visibility makes it faster to explain failed calls, array decay, and dependent-name errors.

10 min
52

Modern C++ / C++11

Don't mix full specialization, partial specialization, and overloading

Full specialization supplies an alternative definition for determined template arguments; partial specialization supplies an implementation for a pattern of arguments. Class templates may be partially specialized; function templates may not. Splitting function behavior usually prefers overloads or constraints, so you do not misjudge how specialization participates in selection.

10 min
53

Modern C++ / C++17

Type traits and if constexpr compile-time branching

Type traits express type properties as compile-time values or type transformations; if constexpr discards inapplicable branches when a template is instantiated. It solves the problem that different types need different well-formed expressions; it does not turn a runtime condition into a compile-time fact.

9 min
54

Modern C++ / C++20

What constexpr, consteval, and constinit each control

constexpr expresses the ability to evaluate as a constant and constraints on variables; consteval requires that an immediate call satisfy constant-expression rules; constinit constrains initialization of variables with static or thread storage duration. The three are not equivalent; in particular constinit does not make a variable read-only.

9 min
55

Modern C++ / C++17

Parameter packs and fold expressions: handle empty packs first

Variadic templates preserve the type of each argument; fold expressions combine a parameter pack into a single expression. Reliable design must first decide the empty-pack result, the initial-value type, and evaluation order. Do not treat the ellipsis as an automatically safe loop or as an array of arbitrary length.

9 min
56

Modern C++ / C++17

optional and variant: put the state in the type

optional expresses that a value may be absent; variant expresses one alternative among a closed set of types. Both manage the lifetime of the object they hold. Safe use depends on determining the current state first, then accessing the correct branch, rather than smuggling state through magic numbers or a bare union.

10 min
57

Modern C++ / C++20

string_view and span: lightweight borrows do not extend lifetime

string_view and span hand the caller an address and a range over contiguous data they do not own. They can cut copies and unify interfaces, but after the original object is destroyed, reallocated, or otherwise invalidated, the view is invalid as well. A read-only view still cannot escape lifetime rules.

10 min
58

Modern C++ / C++20

Concepts and requires: Constraining Callable Interfaces

C++20 concepts put the type properties and expression conditions a template needs onto the interface. A requires expression checks whether a valid operation exists; a requires clause controls candidate viability. They improve diagnostics and overload selection, but they cannot prove that runtime input or business semantics are correct.

10 min
59

Modern C++ / C++20

Ranges and Lazy views: A Pipeline Is Not a Result Cache

C++20 ranges take ranges as algorithm input; views compose lazy operations such as filtering and mapping. Creating a pipeline usually does not compute the full result, and repeated traversal does not promise to reuse results. Understanding underlying ownership, iteration capability, and the final materialization boundary matters more than pipeline syntax.

10 min
60

Modern C++ / C++20

Coroutines: Suspend, Resume, and Coroutine-Frame Ownership

C++20 coroutines let a function suspend and later resume, but they do not automatically create a thread, event loop, or background task. Even a minimal usable abstraction must explicitly manage the coroutine frame, completion state, and exceptions. The synchronous generator below uses exclusive RAII ownership so resources are still released if it ends early.

15 min
61

Modern C++ / C++23

C++23 expected and Confirming Availability by Feature

std::expected<T,E> delivers both the success value and the failure reason as a single return type, suited to anticipated failures that the caller must handle. Enabling C++23 mode does not mean the entire standard library is implemented; you should also check the compiler, the standard-library version, and the corresponding feature-test macros.

10 min
62

Containers & algorithms / C++11

vector: growth, capacity, and invalidation

vector provides contiguous storage and constant-time subscript access, but capacity is not the number of constructed elements. Distinguishing reserve, resize, and reallocation is how you estimate append cost and avoid carrying old pointers, iterators, and past-the-end positions across modifying operations.

9 min
63

Containers & algorithms / C++11

deque: two-ended operations and the limits of stability

deque supports constant-time random access and single-element insertion at either end, yet it does not promise contiguous storage. The important detail is that reference stability is not iterator stability: insertion at the ends keeps references to existing elements but invalidates iterators, and erasure rules still depend on where the change happens.

8 min
64

Containers & algorithms / C++11

list: node stability, splice, and locality

list is strong at insertion, erasure, and node transfer at a known position, not at finding that position quickly. splice can keep element identity and iterators, but allocators and ranges have preconditions; transferring a range across lists is also not always constant time.

9 min
65

Containers & algorithms / C++11

map and set: ordered association and the comparator contract

map and set keep keys ordered by a comparator. Whether a key is a duplicate is decided by comparison equivalence, not necessarily by operator==. Logarithmic lookup, member boundary queries, and keys that must not be mutated casually matter more than remembering the name of some tree.

9 min
66

Containers & algorithms / C++11

unordered: hash, equivalence, and rehash

Unordered containers hash a key to a candidate bucket, then use an equality predicate to identify it. Average-constant lookup is not worst-case constant. Reserving an element count can reduce rehashing, but reference stability, iterator invalidation, and bucket policy still have to be understood separately.

9 min
67

Containers & algorithms / C++20

Iterators: capability categories, ranges, and validity

Iterator categories describe which operations are available and at what complexity; they do not extend object lifetime. Separate single-pass input, multi-pass forward, bidirectional, random-access, and contiguous iterators, then check invalidation from container modifications on its own, before you combine algorithms.

10 min
68

Containers & algorithms / C++11

Algorithms: sort, boundary search, and erase-remove

Standard algorithms operate on ranges, not on container ownership. Sorting needs a valid strict weak ordering, binary boundary search depends on a partition condition, and remove only changes the logical end without shrinking the container. Understanding those preconditions prevents more mistakes than memorizing function names.

10 min
69

Containers & algorithms / C++11

Container adapters: stack, queue, and heap priority

stack, queue, and priority_queue express access discipline through a restricted interface. A priority queue is not a sorted array: the comparator defines who comes before whom, and top takes the largest item in that comparison order. That direction is what makes a min-heap and multi-field priority work.

9 min
70

Containers & algorithms / C++17

Allocator and pmr: choosing a resource and its lifetime

Allocators separate a container's storage-acquisition policy from element management. C++17 pmr lets you choose a memory resource at run time, but the container does not shared-own that resource. The buffer, the resource, and the objects that use them must live and die in the right order.

10 min
71

Concurrency / C++20

Thread lifetime: thread, jthread, and stop_token

A thread object manages an execution resource; it is not the same thing as the thread still running. Decide who is responsible for waiting before you decide how long shared objects may live. C++20 jthread requests stop and waits automatically, but stop still requires cooperation from the work function and cannot forcibly abort a blocking operation.

10 min
72

Concurrency / C++17

Mutual exclusion and RAII: mutex, scoped_lock, and deadlock

A mutex protects the invariant of a set of shared state, not a variable name. Bind the lock's lifetime with RAII. When several objects must be updated together, acquire every required lock in one step. Avoid lock-order cycles, and avoid waiting for a thread or calling unknown code while a lock is held.

10 min
73

Concurrency / C++11

Condition variables: predicates, lost wakeups, and spurious wakeups

A condition variable only lets a thread wait and check again; it does not store the event. Keep the real condition in shared state, modify and inspect it under the same mutex, and wait with a predicate. Then an early notification or a spurious wakeup cannot break the logic.

11 min
74

Concurrency / C++11

Atomic operations: data races, RMW, and lock-free limits

atomic makes accesses to a single atomic object indivisible; it does not turn a multi-step business operation into a transaction. Counter updates need a read-modify-write such as fetch_add. An atomic type also does not promise to be lock-free, and it does not make every algorithm built on it wait-free.

10 min
75

Concurrency / C++20

Memory order: relaxed, acquire-release, and happens-before

Memory order describes how an atomic operation constrains surrounding accesses. relaxed keeps atomicity but does not publish ordinary data. An acquire that reads the corresponding release write is what establishes inter-thread synchronization. Correctness is proved by a happens-before chain, not by an execution order that merely looks stable on one machine.

13 min
76

Concurrency / C++11

Task results: async, future, promise, and launch policy

A future is the receiving end of a one-shot result; it is not a background thread. The launch policy of async chooses independent execution or deferred evaluation. A promise is how a value or exception is submitted by hand. Handle the result, and also be explicit about waiting, exception propagation, and when the associated task ends.

11 min
77

Build & diagnose / C++11

From Source Files to a Program: Compilation and Linking

A compiler seeing a declaration is not the same as a linker finding a definition. Locate errors by preprocessing, compilation, assembly, and linking, then use a local three-file project to understand static libraries, dynamic libraries, and CMake target dependencies; these build styles are toolchain conventions, not language-mandated file formats.

13 min
78

Build & diagnose / C++17

ODR, Header Definitions, and What inline Actually Does

A header can be included by multiple translation units, but definitions in it must satisfy the one-definition rule. inline mainly addresses definitions and entity identity across translation units; it does not force calls to be expanded. Template visibility, name lookup, and consistent build macros are likewise part of interface correctness.

12 min
79

Build & diagnose / C++11

Exception Safety: Guarantees, noexcept, and Commit Points

Exception safety is about what remains of an object after failure, not whether the code contains a catch. Use RAII to retain resources, prepare-then-commit to achieve the strong guarantee, and let noexcept describe only operations that truly do not propagate exceptions; copy-and-swap is a strategy with costs and preconditions, not a universal answer.

12 min
80

Build & diagnose / C++11

Diagnostics and Measurement: Warnings, Sanitizers, and the Debugger

Let compiler warnings, runtime instrumentation, and the debugger each answer different questions, then verify the fix with repeatable inputs. You must distinguish undefined, unspecified, and implementation-defined behavior; a sanitizer reporting nothing only means this run did not trigger the enabled checks, and performance conclusions must also come from independent measurement.

14 min
81

Book practice / C++11

Class invariants: keep illegal states out of objects

A constructor does more than fill members; it is responsible for establishing the object’s promise. Mutating operations must maintain that same promise. Using a capacity-capped stock as an example, putting range checks inside the type and leaving the old value unchanged on failure is more reliable than requiring every caller to check conscientiously.

12 min
82

Book practice / C++11

chrono units: do not turn 1500 milliseconds into 1 millisecond

Time types bind a number to a unit, but count() returns only a bare count. By converting a millisecond budget through a seconds-level interface, observe truncation toward zero, precision loss, and explicit unit boundaries; do not rely on a real clock or sleep, so the results are repeatable.

12 min
83

Book practice / C++11

streambuf layering: give formatted output a different destination

ostream turns values into characters; streambuf delivers the characters. Catch the same set of formatting operations with a fixed-capacity custom buffer, then force a definite capacity shortfall, and observe how a device-layer failure is propagated as the stream's badbit.

14 min
84

Book practice / C++11

Construction failure: the complete object is not destroyed, but members are still cleaned up

When a constructor throws, the incomplete complete object does not have its destructor called, but already-constructed members are destroyed in reverse order. Use an allocation-free event log to trace construction, the throw, and cleanup, distinguishing object lifetime, member lifetime, and allocated storage.

14 min
85

Book practice / C++11

auto is not equal to reference: checking the boundaries of copy and aliasing

auto deduces the type required by the declaration and does not automatically retain the reference properties of the initializer expression. Compare container copying, reference aliasing, and array decay, then use type assertions to fix the intent, avoiding mistaking “omitting the type name” for “saving the copy”.

11 min
86

Book practice / C++11

Value copy versus shared ownership: the same copy, different promises

Whether copying an object copies the data or copies an entry point to the same data must be made clear by the type's interface. Contrast vector's independent values with shared_ptr's shared objects, and use weak_ptr to verify that observers do not extend the resource's lifetime.

12 min
87

Book practice / C++11

Filtering sequences: understand algorithm rearrangement and container erasure separately

An algorithm sees only an iterator range and is not responsible for changing the container's size. Using order-status filtering as an example, distinguish copying to a new sequence, stable partitioning, and erasing the trailing interval, and observe the contracts for empty input, total rejection, and preservation of original order.

12 min
88

Book practice / C++11

Exception safety: prepare first, then commit the state

RAII can reclaim resources when leaving the scope, but it does not automatically undo business state that has already been written. Using configuration replacement to demonstrate how to put work that may fail into a local object, confirm it is valid, then swap, so that the failure path keeps the old configuration unchanged.

13 min
89

Book practice / C++11

Input parsing: read the complete record, validate then commit

Reading an integer from a stream does not prove the entire record is legal. Divide line acquisition, field extraction, range checking, and result committing into stages, so that extra fields, negative values, and bad formats all leave interpretable failure results, without polluting the previous valid record.

13 min
90

Book practice / C++11

Virtual calls during construction: prepare configuration first, then enable the strategy

Virtual calls during construction do not enter a more-derived layer that is not yet ready. Observe the three dispatch phases via safe event logging, then distinguish language-allowed calls from unsound initialization design, and avoid treating override as a lifetime guarantee.

12 min
91

Book practice / C++11

Same-named find, different identity: define the key equivalence relation first

Ordered-set member find uses the equivalence relation defined by the comparator; generic std::find uses equality comparison. Using bucket numbers as an example, observe why the two lookups can give different results, and establish a strict weak ordering that does not violate container requirements.

13 min
92

Book practice / C++11

Polymorphic interfaces do not expose assignment: let leaves keep complete value semantics

Assignment through a base-class reference usually changes only the base subobject and does not represent complete polymorphic copying. Make assignment at the interface layer protected, let concrete leaves use normal copy, and use assignability checks to prove that clients cannot cross this boundary.

12 min
93

Book practice / C++20

Predicates express value conditions, not which call number

Algorithms may copy predicates, and the number of calls is not equal to a position in the container. Separate stable threshold configuration from position operations; use C++20 erase_if to remove elements matching a value condition, then safely perform one explicit position-based erasure.

12 min
94

Book practice / C++11

Sort a lightweight index: keep original data order, and write the invalidation rules clearly

A sorted view can be provided without changing the original records: construct a position index and compare only the keys in the source records. Use a tie-breaking rule to obtain a deterministic result, while stating that the index does not manage the lifetime of the source objects and will not automatically re-sort when data is modified.

13 min
95

Book practice / C++17

Error boundaries: reporting failure is not the same as handling failure

The parsing layer reports errors it can prove; the business layer decides how to respond. Use an amount-parsing interface to distinguish discovery, propagation, and translation, preserve the exception’s dynamic type, and ensure a failure result does not carry a fabricated amount.

12 min
96

Book practice / C++17

Fold expressions: empty input, short-circuit, and evaluation order

When combining multiple conditions into one validator, first define empty-set and post-failure behavior, then choose the fold operator. C++17’s logical-and fold preserves short-circuit, but cannot exempt an invalid template branch from compilation.

11 min
97

Book practice / C++20

Policy-based design: separate decisions, do not duplicate the flow

The same capacity rule can be paired with different overflow-handling approaches. Write a small policy host with member composition and C++20 concepts, distinguishing structural compatibility, semantic commitments, and compile-time configuration versus runtime replacement.

14 min
98

Book practice / C++20

Dimensional types: prevent adding length and time at compile time

Put the exponents of length and time into the type; numeric values are still handled by ordinary arithmetic. This small model demonstrates that addition requires matching dimensions, that multiplication combines dimensions, and that dimensions, unit scales, and numeric safety are clearly distinguished.

14 min
99

Book practice / C++20

A condition variable waits for state, not a single notification

A one-shot computation handoff must simultaneously prove that state is visible, that the wait is not lost, and that the worker thread will not outlive the object's lifetime. Protect the predicate with a mutex and use C++20 jthread to manage termination; whether the notification arrives early or late does not change the answer.

13 min
100

Book practice / C++20

Traits adapt expressions; concepts check boundaries

The same generic algorithm can accept types whose fields and member functions differ, as long as traits provide a consistent operation. Use C++20 requires to catch errors at the interface, and distinguish the three layers of commitment: syntactic satisfaction, return type, and business meaning.

12 min
101

Book practice / C++11

Starting from design constraints: using a value type to uphold interval invariants

D&E Chapter 1 places expressiveness, runtime efficiency, and tool availability in the same engineering problem. This lesson, based on the already-read English sample, designs a small interval value type: it does not rely on inheritance and does not pursue syntactic showmanship, but establishes verifiable invariants at the construction boundary.

9 min
102

Book practice / C++11

During construction and destruction: verify virtual calls, do not guess vtable layout

Implementation diagrams of the object model help in understanding cost, but they are not a cross-compiler ABI promise. This lesson starts from the construction semantics already read in Chapter 5, records behavior across the object lifetime via indirect virtual calls, and distinguishes language guarantees, historical implementation models, and as-yet-uninitialized derived members.

10 min
103

Book practice / C++17

Algorithms and adapters: prove the ranges first, then compose operations

Understanding STL source is not memorizing internal class names, but distinguishing input ranges, output responsibilities, and call contracts. A complete data-processing program connects insert adapters, strict weak ordering, reverse-iterator bounds, and member calls, and shows how old-style function adapters can be rewritten safely.

15 min
104

OSTEP / C11

Preface

Inspired by Feynman's lecture notes, the book is organized around virtualization, concurrency and persistence. It describes problem-first chapters, timelines, dialogues and other devices, plus free access, typical course pacing, and practical notes for both instructors and students.

8 min
105

OSTEP / C11

A Dialogue on the Book

An opening professor-student exchange explains the title's nod to physics lecture notes, frames operating systems around virtualization, concurrency and persistence, recommends combining lectures with rereading notes and real coding projects, and clarifies that the dialogues exist to step outside linear text and think together.

8 min
106

OSTEP / C11

Introduction to Operating Systems

This chapter outlines how an operating system virtualizes limited physical hardware into convenient abstractions while serving as both a resource manager and a standard interface provider.

8 min
107

OSTEP / C11

A Dialogue on Virtualization

A light professor-student conversation that reveals how an operating system turns one physical CPU into many virtual CPUs so every program believes it owns the processor exclusively.

8 min
108

OSTEP / C11

The Abstraction: The Process

This chapter introduces the process as the OS abstraction of a running program, explains CPU virtualization, the composition of process state, and how processes are created from programs.

8 min
109

OSTEP / C11

Interlude: Process API

This interlude presents the core UNIX interfaces for process creation and control. fork duplicates the calling process so parent and child resume from the same return point with different values, wait lets a parent block until a child finishes, and the exec family replaces the entire process image with a new executable. Together they form a compact yet highly expressive API.

8 min
110

OSTEP / C11

Mechanism: Limited Direct Execution

The OS virtualizes the CPU efficiently with limited direct execution: user programs run natively on the processor for speed while hardware mode switches and trap instructions keep the kernel firmly in control.

8 min
111

OSTEP / C11

Scheduling: Introduction

This chapter builds a basic framework for thinking about scheduling policies by first listing simplifying workload assumptions, then introducing turnaround time as the core performance metric, and finally examining two early algorithms—FIFO and shortest-job-first—along with their limits.

8 min
112

OSTEP / C11

Scheduling: The Multi-Level Feedback Queue

The Multi-Level Feedback Queue (MLFQ) dynamically tunes job priorities according to observed runtime behavior, improving both interactive response times and long-job turnaround without a priori knowledge of job lengths.

8 min
113

OSTEP / C11

Scheduling: Proportional Share

This chapter presents a scheduling approach that divides processor time according to assigned ratios. Jobs receive tickets and a random draw selects the next runner; several ticket-handling tricks are described along with why the method is simple to code yet only probabilistically fair.

8 min
114

OSTEP / C11

Multiprocessor Scheduling (Advanced)

As multicore chips become ubiquitous, the OS must assign threads across several CPUs. This chapter originally explains the coherence problems created by per-core caches, why locks remain necessary even with hardware help, and how a scheduler can exploit cache affinity to cut migration costs.

8 min
115

OSTEP / C11

Summary Dialogue on CPU Virtualization

This conversation recaps how an OS virtualizes the CPU through hardware mechanisms and cautious policies, stressing retained control, scheduling trade-offs, and engineering realities in real systems.

8 min
116

OSTEP / C11

A Dialogue on Memory Virtualization

The conversation makes clear that CPU virtualization is only the beginning; memory virtualization is the real challenge. Every address a user program produces is virtual. With hardware help the OS translates those addresses into physical ones, giving each process the illusion of a large, private, contiguous memory. The illusion simplifies programming and also isolates processes from one another. Later chapters start with base-and-bounds and then add TLBs and multi-level page tables.

8 min
117

OSTEP / C11

The Abstraction: Address Spaces

This chapter shows how an operating system abstracts physical RAM into a private address space per process so that many programs can reside in memory at once, run safely, and still appear to own a large contiguous region starting at address zero.

8 min
118

OSTEP / C11

Interlude: Memory API

C programs rely on automatic stack allocation together with explicit heap requests to control data lifetime. Mastering the pairing of malloc and free plus typical misuse patterns is essential for robust software.

8 min
119

OSTEP / C11

Mechanism: Address Translation

This chapter presents hardware address translation as the mechanism that lets an OS virtualize memory efficiently and flexibly. Hardware maps every virtual address to a physical one on the fly, giving each process the illusion of a private contiguous space starting at zero while the OS retains isolation and protection.

8 min
120

OSTEP / C11

Segmentation

Segmentation equips the MMU with a distinct base-and-limit pair per logical region so that code, heap and stack can reside in separate physical holes and unused virtual gaps occupy no RAM.

8 min
121

OSTEP / C11

Free-Space Management

This chapter explains the core difficulties allocators face with variable-sized free regions, focusing on why external fragmentation occurs and how splitting, coalescing, and header recording help keep usable contiguous space available.

8 min
122

OSTEP / C11

Paging: Introduction

Paging carves both virtual address spaces and physical memory into identical fixed-size pages and frames, eliminating external fragmentation. A private page table per process records the mappings so hardware can replace a virtual page number with a physical frame number.

8 min
123

OSTEP / C11

Paging: Faster Translations (TLBs)

Paging would be too slow without a hardware cache of translations. The TLB exploits locality so that most address translations complete in a few cycles instead of requiring a memory access.

8 min
124

OSTEP / C11

Paging: Smaller Tables

Linear page tables devour huge amounts of RAM. This chapter uses fresh wording to explore larger pages and a paging-plus-segmentation hybrid that shrink the tables, while highlighting the internal-fragmentation and extra hardware checks they introduce.

8 min
125

OSTEP / C11

Beyond Physical Memory: Mechanisms

The OS employs slower secondary storage as swap area plus a present bit in each PTE so that many large address spaces can coexist even when they do not fit in RAM. Missing pages raise faults that a software handler resolves by transferring data from disk.

8 min
126

OSTEP / C11

Beyond Physical Memory: Policies

When physical memory is scarce the operating system must select pages to send to disk. This chapter discusses how to design replacement policies that reduce page faults, using the unrealizable optimal algorithm as a benchmark while examining the simple FIFO method and its limitations.

8 min
127

OSTEP / C11

Complete VM Systems

Using VAX/VMS and Linux as concrete examples, this chapter shows how page-table designs, TLB handling, page replacement and extra features for performance, security and functionality are combined into a complete virtual-memory system that works from embedded devices to supercomputers.

8 min
128

OSTEP / C11

Summary Dialogue on Memory Virtualization

A student-professor recap that builds a working mental model of virtual memory: programs see only virtual addresses, the TLB makes translation practical, page-table designs must flexibly support sparse spaces, and swapping exposes real hardware limits. The aim is independent diagnosis of unexpected system behavior.

8 min
129

OSTEP / C11

A Dialogue on Concurrency

A professor and student introduce concurrency via the everyday scene of many people grabbing peaches from a table, showing that uncoordinated simultaneous grabs cause conflicts while lining up guarantees fairness at the cost of speed. The ideal solution must be both correct and fast. The analogy then maps onto multi-threaded programs: threads act as independent agents and shared memory locations resemble the peaches, so access must be coordinated. OS courses cover this topic because the kernel both supplies synchronization primitives to applications and, as the original concurrent program, must itself manage internal data with extreme care.

8 min
130

OSTEP / C11

Concurrency: An Introduction

This chapter presents threads from a fresh angle: a single process may contain several independent flows of execution that all share one address space. Every thread carries its own program counter and registers, so a switch among them leaves the page table untouched. Each thread also owns a private stack. Threads exist mainly so that multiple cores can work in true parallel and so that a program can keep making progress while some of its threads wait for I/O.

8 min
131

OSTEP / C11

Interlude: Thread API

This interlude surveys the core POSIX thread-library calls used to launch new flows of execution, wait for them to finish, and protect shared data with mutexes. The interfaces balance ease of use with flexibility; later chapters expand on locks and condition variables through many examples.

8 min
132

OSTEP / C11

Locks

Locks let programmers protect critical sections so that updates to shared data occur atomically, avoiding race conditions among concurrent threads.

8 min
133

OSTEP / C11

Lock-based Concurrent Data Structures

This chapter examines how locks can be added to ordinary data structures to achieve thread safety, analyzes the performance limitations of naive locking, and presents approximation techniques that improve scalability, with counters serving as the running example.

8 min
134

OSTEP / C11

Condition Variables

Condition variables let a thread sleep efficiently until a shared condition becomes true, avoiding useless spinning. They must be used together with a mutex: wait atomically drops the lock and sleeps, signal wakes a waiter, and an explicit state variable prevents lost signals.

8 min
135

OSTEP / C11

Semaphores

A semaphore coordinates threads with an integer counter plus blocking and wakeup primitives. Its initial value decides whether it behaves as a mutex or an event notifier. This chapter uses original examples to show wait/post semantics, binary usage, and parent-child ordering, plus a compilable C demo.

8 min
136

OSTEP / C11

Common Concurrency Problems

This chapter analyzes recurring defect patterns in concurrent software, highlighting the distinction between deadlocks and non-deadlock issues, the latter mainly involving failed atomicity assumptions and reversed execution orders. Synchronization primitives can effectively mitigate these risks and improve the reliability of multithreaded code.

8 min
137

OSTEP / C11

Event-based Concurrency (Advanced)

This chapter presents a way to build concurrent servers without threads. The program centers on an event loop that processes one arriving event at a time, giving the developer full scheduling control and removing any need for locks. The essential restriction is that handlers must never perform operations that can block.

8 min
138

OSTEP / C11

Summary Dialogue on Concurrency

This summary explores the mental challenges of concurrent execution and stresses writing reliable concurrent programs through simplified designs and proven patterns.

8 min
139

OSTEP / C11

Dialogue on the Topic of Persistence

This original dialogue employs fresh analogies to explain how operating systems keep information alive after shutdowns or failures, revealing the extra effort and design intrigue behind persistent storage.

8 min
140

OSTEP / C11

I/O Devices

This chapter explains how an operating system incorporates input/output devices into the overall machine, covering hierarchical bus layouts, the registers a device exposes, the polling-based request protocol, and the use of interrupts so computation can overlap with device work.

8 min
141

OSTEP / C11

Hard Disk Drives

This chapter explains how hard disks persist data as a sector array, the platter-track-head geometry, and how seek plus rotational delay dominate access cost. Schedulers reorder requests to raise effective throughput.

8 min
142

OSTEP / C11

Redundant Arrays of Inexpensive Disks (RAID)

RAID organizes multiple inexpensive disks into an array that simultaneously improves capacity, throughput and fault tolerance while remaining completely transparent to the host. This chapter covers the external interface, the assumed fault model, the three evaluation axes and the simplest striping organization.

8 min
143

OSTEP / C11

Interlude: Files and Directories

This chapter presents an original view of how an operating system virtualizes persistent devices as two complementary abstractions—files and directories—and how the classic UNIX interface of open, read, write and unlink hides inode numbers behind human-readable path names.

8 min
144

OSTEP / C11

File System Implementation

This chapter uses a minimal vsfs example to show how core on-disk structures can be designed entirely in software to manage files, focusing on the division of labor among the superblock, bitmaps, inode table and data region, plus how system calls map onto those structures.

8 min
145

OSTEP / C11

Locality and The Fast File System

The original UNIX file system treated the disk as random-access memory: inodes sat far from data, free space fragmented, and 512-byte blocks forced extra seeks, yielding only a few percent of possible bandwidth. The Fast File System introduced cylinder (now block) groups plus simple locality heuristics that co-locate related files and metadata, turning long seeks into short ones and restoring sequential transfer rates.

8 min
146

OSTEP / C11

Crash Consistency: FSCK and Journaling

File systems keep inodes, bitmaps and data blocks on disk; one operation often needs several writes. A crash can leave a partial update and inconsistency. This chapter originally explains fsck-style later scanning plus journaling (write-ahead logging) that recovers quickly with modest extra work.

8 min
147

OSTEP / C11

Log-structured File Systems

Log-structured file systems buffer every update including metadata in memory then flush large sequential segments onto free disk space, matching write-dominated traffic from bigger caches, nearing peak bandwidth and easing RAID small-write costs.

8 min
148

OSTEP / C11

Flash-based SSDs

This chapter introduces how NAND flash forms modern solid-state drives, focusing on the physical requirement to erase an entire block before programming any page, cell wear-out, and how these traits shape storage-system design.

8 min
149

OSTEP / C11

Data Integrity and Protection

This chapter studies how storage systems keep written data unchanged despite imperfect hardware. It covers partial disk faults (latent sector errors and silent corruptions), redundancy-based recovery, and checksum detection, highlighting the space-time trade-offs involved.

8 min
150

OSTEP / C11

Summary Dialogue on Persistence

This dialogue recaps the core difficulties of persistent storage: data must survive crashes, updates require reliable recovery, plus disk scheduling, RAID, checksums and device-aware file-system designs. The same ideas remain useful with flash.

8 min
151

OSTEP / C11

A Dialogue on Distribution

A professor-student conversation introduces the core idea of distributed systems, highlights unreliability across machines, and sketches replication plus retry as ways to stay available, setting the stage for later distributed-file-system material.

8 min
152

OSTEP / C11

Distributed Systems

Distributed systems assemble many machines over a network into one service. Individual hosts, disks and links fail, yet redundancy can make the whole appear almost never to fail. Communication is inherently lossy, so checksums, acknowledgements and retransmissions are required to build usable protocols.

8 min
153

OSTEP / C11

Network File System (NFS)

This chapter introduces the early successful distributed file system NFS, focusing on how the client-server model enables data sharing and transparent access, and how NFSv2 achieves instant recovery after server crashes via a completely stateless protocol.

8 min
154

OSTEP / C11

Andrew File System (AFS)

This chapter explores how AFS attains high scalability through whole-file caching on client local disks plus server-driven callbacks that cut server load, contrasting the approach with NFS polling and tracing protocol changes across versions.

8 min
155

OSTEP / C11

Summary Dialogue on Distribution

This summary uses a light dialogue to recap core ideas from distributed systems. Component failures are inevitable, yet deploying many disks or machines can conceal most of them. Simple mechanisms such as retries handle transient problems effectively. The exact bits exchanged in protocols govern both failure response and scalability. The conversation closes humorously, underscoring that learning never truly ends.

8 min
156

OSTEP / C11

A Dialogue on Security

This dialogue introduces operating system security, highlighting differences from reliability due to intentional adversaries. It covers the need to protect confidential, intact, and available resources, plus the challenges of dealing with intelligent persistent attackers.

8 min
157

OSTEP / C11

A Few Words About Security

This chapter introduces the importance of operating system security, explaining why the OS as the foundation of all computing must be protected, and discusses the challenges in achieving security.

8 min
158

OSTEP / C11

Authentication

An operating system must reliably identify the principal behind every process before it can enforce security policy. This chapter examines how identities are attached to processes through inheritance and through the initial binding that occurs at login.

8 min
159

OSTEP / C11

Access Control

This chapter shows how an operating system converts a security policy into a concrete allow-or-deny verdict for every resource request, emphasizing the duties of the reference monitor, the subject-object model, and the efficiency-versus-flexibility trade-offs of access-control lists versus capabilities.

8 min
160

OSTEP / C11

Cryptography

An operating system cannot protect data after it leaves the hardware the kernel actually controls. Cryptography uses a key to turn plaintext into ciphertext so that later possession of the bits still yields neither meaning nor useful alteration. This chapter presents the symmetric-encryption model, the decisive role of key secrecy, and how a hash supplies integrity checking.

8 min
161

OSTEP / C11

Distributed System Security

This chapter examines the distinctive security problems of distributed systems, where a single operating system cannot govern remote hosts or the intervening network. Authentication by passwords or public keys, together with certificates issued by trusted authorities, supplies the practical tools for establishing identity and protecting communication.

8 min
162

OSTEP / C11

Virtual Machines

A virtual machine monitor inserts a transparent abstraction layer between hardware and operating systems so multiple guest OSes can run concurrently, each believing it owns the machine. This appendix covers historical background, contemporary uses, and key mechanisms for CPU virtualization.

8 min
163

OSTEP / C11

Monitors

This appendix presents monitors as a construct that packages shared data with its access operations into one module while automatically supplying mutual exclusion, uses condition variables for wait-and-signal, and contrasts Hoare versus Mesa semantics as they appear in real implementations.

8 min