FREE COURSE / REAL PRACTICE
Modern C++ & systems programming
Learn values, ownership and generic code, then apply them to containers, algorithms, concurrency and native systems.
What you’ll work toward
Build C++ programs with explicit lifetime and interface contracts, then investigate correctness and performance with the supplied tools.
Read an explanation, inspect the diagrams and work through the available checks, debugging exercises and builds. Feedback and prerequisite links guide the next step.
Before you start
The entry lesson has no earlier CodeRigor skill prerequisite. Start there and follow the sequence.
Individual lessons can add prerequisites. The course map shows your actual readiness.
A look inside the first lesson
#include <print>
#include <string>
int main() {
std::string a = "hello";
std::string b = a; // b is a copy
b += ", world";
std::println("a = {}, b = {}", a, b); // a is unchanged
}Your course outline
Follow the lessons in curriculum order. Open a unit to preview the ideas you’ll work with.
Foundations
- LESSON 01.01
Values, references and const
Choose deliberately between copying, aliasing and pointing; write const-correct APIs; never let a reference outlive its object.
Open lesson - LESSON 01.02
std::vector, std::span and std::string_view
Own sequences with std::vector, pass them around with std::span and std::string_view, and never let a view outlive what it looks at.
Open lesson - LESSON 01.03
RAII, scope and object lifetime
Tie every resource to an object's lifetime so cleanup happens exactly once — on normal exit, early return and exceptions.
Open lesson - LESSON 01.04
Big-O and measuring
Count the work a loop does, know the cost of standard operations, and measure growth honestly with a log-log slope.
Open lesson - LESSON 01.05
Binary search
Find the first position where a monotone predicate becomes true, in O(log n), with a loop invariant you can state.
Open lesson
Owning things
- LESSON 02.01
Classes: invariants and the rule of zero/five
Design classes that establish and keep an invariant, let the compiler write the special members (rule of zero), and know exactly when it can't.
Open lesson - LESSON 02.02
Move semantics and value categories
Know which expressions can be moved from, write correct noexcept move operations, and know when the compiler elides copies for you.
Open lesson - LESSON 02.03
Dynamic array (your own vector)
Separate raw storage from live objects, grow geometrically for amortized O(1) push_back, and keep ownership, aliasing and exceptions straight.
Open lesson - LESSON 02.04
Stacks, queues and ring buffers
LIFO and FIFO, the standard adaptors, and a growable ring buffer with O(1) push and pop at both ends of its life.
Open lesson - LESSON 02.05
Hash maps and sets in practice
Use std::unordered_map and unordered_set for O(1)-average counting, grouping and lookup — and know their traps: operator[] inserts, order is unspecified, the hash decides your complexity.
Open lesson - LESSON 02.06
Two pointers and sliding windows
Replace nested loops with two indices that only move forward: pair sums on sorted data, in-place compaction, and windows that grow and shrink under an invariant — all in O(n).
Open lesson
Generic code
- LESSON 03.01
Templates and concepts
Write generic code that says what it needs: templates, deduction, concepts and requires-clauses, folds, and C++26 pack indexing.
Open lesson - LESSON 03.02
Iterators and ranges basics
Know what each iterator category promises, make your own container work with std::ranges, and use sentinels, projections and simple views.
Open lesson - LESSON 03.03
Errors as values: optional and expected
Return "maybe a value" and "a value or an error" as types, chain them without nested ifs, and know when an exception is the better tool.
Open lesson - LESSON 03.04
Linked lists
Node-based sequences: sentinels that delete edge cases, O(1) splicing, iterative reversal and teardown, fast/slow pointers — and why they lose to vectors on modern hardware.
Open lesson - LESSON 03.05
Insertion sort and merge sort
Two stable sorts with opposite strengths: insertion sort (simple, adaptive, great for small or nearly sorted input) and merge sort (O(n log n) always, O(n) extra space).
Open lesson
Hashing and heaps
- LESSON 04.01
Smart pointers and ownership
Decide who owns what — unique, shared or borrowed — and express it with unique_ptr, shared_ptr, weak_ptr and plain references, without leaks, cycles or double frees.
Open lesson - LESSON 04.02
Lambdas and callables
Write lambdas with deliberate captures, and pick the right callable type for an API: a template, std::function_ref, std::function or std::move_only_function.
Open lesson - LESSON 04.03
Hash tables: open addressing
Build a flat hash map: mix the hash, probe linearly in a power-of-two array, keep the load factor bounded, and delete without breaking probe chains.
Open lesson - LESSON 04.04
Binary heaps and priority queues
Keep the largest element on top of an array-shaped tree: sift up and down in O(log n), build a heap in O(n), and use std::priority_queue without its traps.
Open lesson - LESSON 04.05
Partitioning, quicksort and selection
Partition around a pivot with a precise invariant, then build quicksort and quickselect on it — and make them survive sorted, reversed and all-equal input.
Open lesson
Compile time and trees
- LESSON 05.01
Compile-time programming
Move work to compile time with constexpr, consteval and constinit — and let the compiler reject undefined behaviour for you.
Open lesson - LESSON 05.02
std::format and std::print
Type-safe, compile-time-checked formatting: the replacement-field grammar, ranges, allocation-free output, runtime patterns, and custom formatters.
Open lesson - LESSON 05.03
Flat containers: flat_map and inplace_vector
Sorted-vector maps for read-mostly data, and fixed-capacity vectors that never allocate — when they beat node-based and heap-based containers, and what they cost.
Open lesson - LESSON 05.04
Binary trees and binary search trees
Traverse trees in every order, keep the BST invariant through insert and erase, and never let a degenerate tree overflow your stack.
Open lesson - LESSON 05.05
Recursion and backtracking
Trust the smaller problem; then search a decision tree with choose → explore → un-choose, pruning dead branches and skipping duplicate ones.
Open lesson
Sum types, contracts, graphs
- LESSON 06.01
Sum types and value-semantic polymorphism
Model closed sets of alternatives with std::variant and exhaustive visitors, build recursive value types with std::indirect, and get copyable open hierarchies with std::polymorphic instead of unique_ptr plus clone().
Open lesson - LESSON 06.02
Contracts (C++26)
State what callers must ensure and what a function promises with pre, post and contract_assert — and know exactly what happens when they're broken.
Open lesson - LESSON 06.03
Balanced search trees
Keep a search tree's height logarithmic with rotations: AVL balance factors, red-black colours, and why std::map is built the way it is.
Open lesson - LESSON 06.04
Graphs: representation, BFS and DFS
Store graphs so neighbours are cheap to visit, then explore them breadth-first (shortest paths, layers) and depth-first (components, cycles, colourings) without blowing the stack.
Open lesson - LESSON 06.05
Union-find (disjoint sets)
Track which elements are connected as you merge groups: a parent array, union by size and path compression give near-constant time per operation.
Open lesson
Pipelines and memory
- LESSON 07.01
Ranges: views and pipelines
Compose lazy views with |, materialise with ranges::to, fold, generate with std::generator, and know where views dangle or cache.
Open lesson - LESSON 07.02
Allocators and std::pmr
Control where containers get their memory: the allocator model, propagation traits, polymorphic memory resources, arenas, and the lifetime rules that keep them safe.
Open lesson - LESSON 07.03
Shortest paths and topological order
Dijkstra with a heap and lazy deletion, 0-1 BFS, topological order with Kahn's algorithm, and longest paths in a DAG — with 64-bit distances and cycle detection.
Open lesson - LESSON 07.04
Dynamic programming I
Turn exponential recursion into polynomial time: name the state, write the recurrence, then memoize, tabulate and shrink the table.
Open lesson - LESSON 07.05
Memory layout, alignment and caches
Know what your objects look like in memory: padding and member order, alignment, empty members, object representation without UB, and laying data out for the cache.
Open lesson - LESSON 07.06
Fixed-capacity containers: no hidden allocations
Game- and embedded-style containers in the spirit of EASTL: inline storage with an optional heap overflow, small-buffer optimisation, fixed node pools — and why a frame budget bans surprise allocations.
Open lesson
Concurrency
- LESSON 08.01
Threads, jthread and cooperative cancellation
Start, stop and join threads safely: jthread and stop tokens for cancellation, mutexes and condition variables without races or deadlocks, futures for results.
Open lesson - LESSON 08.02
Atomics and the C++ memory model
Share data between threads without locks: atomic operations, compare-exchange loops, and the memory orders (relaxed, acquire/release, seq_cst) that decide what other threads are guaranteed to see.
Open lesson - LESSON 08.03
std::execution: senders and receivers
Understand C++26's async model — lazy senders, receivers with three completion channels, operation states — by building a small standards-shaped implementation of just, then, when_all and sync_wait.
Open lesson - LESSON 08.04
Lock-free data structures: the Treiber stack
Build a stack that many threads push and pop without locks: a CAS loop on the head pointer, the ABA problem, and why a popped node can't simply be deleted.
Open lesson - LESSON 08.05
Safe memory reclamation: hazard pointers and RCU
Free nodes of a lock-free structure safely and promptly: hazard pointers that protect what a thread is reading, and epoch-based RCU that frees an old version only after every reader that could see it has moved on.
Open lesson
Reflection and advanced structures
- LESSON 09.01
Static reflection (C++26)
Inspect types, members and enumerators at compile time with ^^ and std::meta, splice them back with [: :], and generate to_string, equality and hashing instead of writing them by hand.
Open lesson - LESSON 09.02
Modern pack tricks: indexing, binding packs and friends
Index packs directly with Ts...[I], destructure tuples and aggregates into packs with auto [...xs], and use structured bindings as conditions and _ placeholders — the C++26 features that retire most index_sequence boilerplate.
Open lesson - LESSON 09.03
Tries and prefix structures
Store strings as paths in a tree of characters, so prefix questions — how many words start with this, what are the first k completions — cost time proportional to the prefix, not to the dictionary.
Open lesson - LESSON 09.04
Range queries: Fenwick and segment trees
Answer range sums, minimums and friends while the data keeps changing: Fenwick trees for prefix sums, segment trees for any monoid, lazy propagation for range updates — all O(log n).
Open lesson - LESSON 09.05
String algorithms: KMP, Z and hashing
Find patterns in O(n + m) by never re-reading text you already matched: borders and the prefix function (KMP), the Z-function, periods, and rolling hashes that are verified, not trusted.
Open lesson
Performance
- LESSON 10.01
Profiling and benchmarking
Measure before optimising: honest timing loops, the right statistic, keeping the optimiser from deleting your benchmark, and reading perf counters.
Open lesson - LESSON 10.02
SIMD and auto-vectorisation
Make one instruction do four (or sixteen) lanes of work: what compilers vectorise on their own and why they refuse, then explicit portable SIMD with exact tails, masks and reductions.
Open lesson - LESSON 10.03
Data-oriented design
Design around the data and how it's accessed: hot/cold splits, struct-of-arrays, dense storage with generational handles instead of pointers, batching by type, and branch-friendly data.
Open lesson - LESSON 10.04
Dynamic programming II
Richer DP states — two strings, intervals, subsets as bitmasks, subtrees, DAGs and digits — plus reconstruction, rolling memory and the classic speed-ups.
Open lesson - LESSON 10.05
Intrusive and structure-of-arrays containers
Containers that don't own their elements' memory or layout: intrusive lists (the link lives in the object), sorted-vector maps, structure-of-arrays tuple vectors, segmented vectors and bit vectors — the EASTL toolbox and when each one pays.
Open lesson
x86-64: reading the machine
- LESSON 11.01
x86-64 registers and data movement
Read and write the instructions that move data: the sixteen registers and their sub-registers, zero- and sign-extension, lea as arithmetic, and every addressing mode the compiler uses for arrays, structs and globals.
Open lesson - LESSON 11.02
The System V calling convention
Where arguments and return values live on x86-64 Linux: integer and floating-point argument registers, stack arguments, structs in registers or behind a hidden pointer, callee-saved registers and the 16-byte stack alignment rule.
Open lesson - LESSON 11.03
x86-64 control flow: flags, jumps, setcc and cmov
Read and write the instructions behind every if, loop and switch: cmp/test and the flags, signed versus unsigned condition codes, setcc and cmov for branch-free code, rotated loops and jump tables.
Open lesson - LESSON 11.04
x86-64 stack frames and calls
What call and ret really do, prologues and epilogues, frame pointers, locals, spills and the red zone, 16-byte alignment, stack arguments, tail calls, and how -O0 and -O2 frames differ.
Open lesson
x86-64: what the compiler does
- LESSON 12.01
Reading optimised code
Recognise what -O2 did to your code: inlining, folding, strength reduction, division by magic numbers, dead stores, hoisting, devirtualisation, and the optimisations undefined behaviour licenses.
Open lesson - LESSON 12.02
Writing functions in assembly
Write whole functions in x86-64 assembly (GAS, Intel syntax): loops over arrays and strings, pointer walking, conditional moves, and calling back into C++ while keeping the ABI's promises.
Open lesson - LESSON 12.03
Inline assembly, builtins and barriers
GNU extended asm done right — outputs, inputs, constraints, clobbers, earlyclobbers, volatile and asm goto — and why builtins and intrinsics are usually the better tool. Plus rdtsc, cpuid, and compiler barriers versus CPU fences.
Open lesson - LESSON 12.04
Branchless code and bit tricks
cmov, setcc and sbb; when a branch beats a select and when it loses badly; and the bit-manipulation instructions behind std::popcount, countl_zero, rotl and pext.
Open lesson
x86-64: SIMD, memory order, the core
- LESSON 13.01
SSE and AVX2 intrinsics
Program the vector unit directly: xmm/ymm lanes, unaligned loads, compare masks and movemask, the 128-bit lane trap in shuffles, horizontal reductions and exact tails, with AVX2 enabled per function.
Open lesson - LESSON 13.02
Auto-vectorization: reading and steering it
Read the compiler's vector code, know exactly why a loop wasn't vectorized (aliasing, dependencies, float reductions, early exits, strides), and rewrite it so it is — checked against the real codegen.
Open lesson - LESSON 13.03
The x86-64 memory model (TSO)
What x86 hardware actually reorders (only a store followed by a load, through the store buffer), what each std::atomic order compiles to, and why the compiler can still break code the hardware wouldn't.
Open lesson - LESSON 13.04
The core underneath: latency, throughput, caches
How an out-of-order x86 core actually runs your loop: uops and ports, latency versus throughput, dependency chains and multiple accumulators, llvm-mca, cache lines, false sharing, store forwarding — and why microbenchmarks lie.
Open lesson
AArch64: reading the machine
- LESSON 14.01
AArch64 registers, loads and constants
Read and write AArch64 data movement: x/w registers and the zero register, sized and sign-extending loads, the register-offset, pre- and post-index addressing modes, building 64-bit constants with movz/movk, and bitfield extracts.
Open lesson - LESSON 14.02
The AArch64 calling convention (AAPCS64)
Where AArch64 functions find their arguments and leave their results: x0–x7 and v0–v7, the x8 indirect result, callee-saved x19–x28 and d8–d15, frame records with fp and lr, 16-byte sp alignment, and how structs are passed (HFAs, ≤ 16 bytes in registers, larger by reference).
Open lesson - LESSON 14.03
AArch64 control flow: NZCV, b.cond, csel and ccmp
Read and write the instructions behind every if, loop and switch on AArch64: the NZCV flags, signed versus unsigned condition codes, cbz/tbz shortcuts, the conditional-select family (csel, cset, cinc, csneg), ccmp chains for && without branches, rotated loops and jump tables.
Open lesson - LESSON 14.04
Writing functions in AArch64 assembly
Write whole functions in AArch64 assembly (GAS): frame records with stp/ldp, saving callee-saved registers in pairs, post-index loops over arrays and strings, and calling back into C++ with blr while keeping sp 16-byte aligned.
Open lesson
AArch64: SIMD, ordering, codegen
- LESSON 15.01
NEON intrinsics
Program AArch64's Advanced SIMD unit directly: 32 registers of 128 bits in 16B/8H/4S/2D arrangements, compares that make all-ones masks, across-lane reductions, widening and narrowing, de-interleaving loads, and life without movemask.
Open lesson - LESSON 15.02
SVE: vector-length-agnostic SIMD
Write SIMD code that runs at any vector length from 128 to 2048 bits: svcnt*, while-predicates instead of scalar tails, merging vs zeroing predication, predicated loads, widening loads and reductions.
Open lesson - LESSON 15.03
The AArch64 memory model
What weakly ordered ARM hardware may reorder (almost everything), what ldar/stlr/ldapr and dmb buy you, how atomic read-modify-writes compile (LL/SC, LSE, outline atomics), and why code that works on x86 breaks here.
Open lesson - LESSON 15.04
AArch64 codegen, side by side with x86-64
The same C++ on both machines: fused multiply-add and conditional select, shifted operands, bitfield instructions, immediates that don't fit, conditional compare chains, load/store pairs — and how to write C++ that lands on the good idioms.
Open lesson
Microcontrollers: the bare machine
- LESSON 16.01
From reset to main: vector tables, startup code, linker scripts
What a Cortex-M does between power-on and main: the vector table, the reset handler's chores (FPU, .data, .bss, constructors), linker scripts with VMA/LMA and their symbols, and the board's memory map.
Open lesson - LESSON 16.02
Memory-mapped I/O and volatile
Talk to hardware through memory-mapped registers: what volatile guarantees (and doesn't), register structs, read-modify-write and write-1-to-clear registers, why bitfields and hardware don't mix, and a polling UART driver.
Open lesson - LESSON 16.03
Typed registers: zero-cost MMIO in modern C++
Wrap memory-mapped registers in templates — Reg<address, access>, Field<reg, offset, width, type> — so wrong accesses don't compile and right ones cost exactly the ldr/bfi/str you'd write by hand.
Open lesson - LESSON 16.04
Freestanding C++: no OS, no heap, small budgets
Write C++ for a microcontroller: what the freestanding library gives you, static storage instead of the heap, -fno-exceptions and -fno-rtti and what they change in the code, constinit, and error handling with std::expected.
Open lesson
Microcontrollers: time, interrupts, data
- LESSON 17.01
Interrupts: SysTick, timers and the NVIC
The Cortex-M exception model in practice: vector table, NVIC enable/pending/priority, SysTick and timer interrupts, what the hardware stacks, why an ISR must clear its source, and sleeping with WFI — built into a tick clock with software timers.
Open lesson - LESSON 17.02
Critical sections and ISR-safe data
Sharing data between interrupt handlers and main code: torn reads, lost updates, PRIMASK guards that nest, what std::atomic compiles to on a Cortex-M4, and a lock-free queue between an ISR and the main loop.
Open lesson - LESSON 17.03
Interrupt-driven I/O
Drivers that don't busy-wait: an interrupt-driven UART transmitter fed from a ring buffer, starting and stopping the TX interrupt, backpressure, formatting without the heap, timer-driven work, event-driven state machines, and DMA as a concept.
Open lesson - LESSON 17.04
Fixed-point arithmetic and the M4 DSP instructions
Q15, Q31 and Q16.16: conversion and rounding, widening multiplies, saturation, the Cortex-M4's DSP instructions (ssat, qadd, smulbb, smlad, smlald), when the single-precision FPU is the better tool and why double is software, and FIR filters that don't overflow.
Open lesson
Vim (optional)
- LESSON 18.01
Vim basics: modes, hjkl, insert and delete
Normal vs insert mode, moving with h j k l, inserting with i a o A, deleting with x.
Open lesson - LESSON 18.02
Vim words: w b e, W B E, 0 ^ $
Move by words and WORDs instead of characters, and jump to line starts and ends.
Open lesson - LESSON 18.03
Vim text objects: iw aw, i( a(, i" a"
Edit whole words, bracket contents and strings from anywhere inside them.
Open lesson - LESSON 18.04
Vim operators: d c y with motions, counts and .
Combine operators with motions, repeat them with counts and the dot command.
Open lesson - LESSON 18.05
Vim search and repeat: f t ; , / * n
Jump straight to characters and words, and repeat jumps and edits.
Open lesson
Graphics: 3D math, cameras, rasterization
- LESSON 19.01
3D math for graphics: vectors and matrices
vec3 and mat4 the way renderers use them: dot and cross, points vs directions, homogeneous coordinates, column-major storage, TRS composition, rigid and general inverses, the normal matrix, and float precision.
Open lesson - LESSON 19.02
Quaternions for rotation
Unit quaternions as 3D Gaussian splatting uses them: Hamilton product, rotating vectors with q v q*, the half angle, the exact quaternion-to-matrix formula, double cover, slerp vs nlerp, and why not Euler angles.
Open lesson - LESSON 19.03
Cameras and projection
The pinhole camera end to end: world-to-camera extrinsics, intrinsics from a field of view, projecting points to pixels, one primary ray per pixel centre, OpenGL's projection matrix and NDC depth — and the OpenCV-vs-OpenGL axis conventions that break most radiance-field loaders.
Open lesson - LESSON 19.04
Triangle rasterization
Turn screen-space triangles into pixels the way GPUs do: edge functions, bounding boxes, the top-left fill rule, barycentrics, a z-buffer, perspective-correct interpolation and back-face culling.
Open lesson
Graphics: rays, light, space
- LESSON 20.01
Ray intersections: spheres, triangles, boxes
Shoot rays at geometry the way a path tracer does: a numerically stable ray–sphere quadratic, Möller–Trumbore triangles with barycentrics, the slab test with IEEE infinities and its NaN trap, closest hit, and shadow acne.
Open lesson - LESSON 20.02
Bounding volume hierarchies
Make ray casting O(log n): a flattened 32-byte-node BVH built with the binned surface area heuristic, closest-first stack traversal with pruning, any-hit queries, refitting for animation, and how LBVH and RT hardware (BLAS/TLAS) fit in.
Open lesson - LESSON 20.03
Shading and Monte Carlo light transport
Radiance and the rendering equation, Lambert and GGX BRDFs, Monte Carlo estimators with cosine-weighted importance sampling, a branchless frame around the normal, Russian roulette, and lighting in linear space before the sRGB encode.
Open lesson - LESSON 20.04
Morton codes and linear octrees
Put 3D data in spatial order: quantise to a 21-bit grid, interleave bits into Morton codes with magic-number spreading, radix-sort, read a linear octree off the common prefixes, and answer cell and radius-neighbour queries — the ordering behind point-cloud and splat compression, LOD and k-NN.
Open lesson
Graphics: neural rendering
- LESSON 21.01
Volume rendering for NeRF
Turn densities and colours along a ray into a pixel: the volume rendering integral and its alpha-compositing quadrature, transmittance, weights and depth, stratified and inverse-CDF hierarchical sampling, and NeRF's positional encoding.
Open lesson - LESSON 21.02
Spherical harmonics for view-dependent colour
Evaluate degree-3 real spherical harmonics exactly like 3D Gaussian Splatting — constants, signs, +0.5 and clamp — and project functions on the sphere onto them by Monte Carlo.
Open lesson - LESSON 21.03
Multiresolution hash grid encoding
Instant-NGP's input encoding: L grids of geometric resolution, coarse ones stored densely and fine ones through a spatial hash, trilinear lookups concatenated for a tiny MLP — and the scatter-add backward pass that trains the tables.
Open lesson - LESSON 21.04
3D Gaussian Splatting: the rasterizer
Render millions of anisotropic 3D Gaussians in real time: Σ = R S Sᵀ Rᵀ, EWA projection to a screen-space conic, 16×16 tile binning with one radix sort on (tile, depth) keys, and front-to-back alpha blending — the reference CUDA rasterizer, rebuilt on the CPU.
Open lesson - LESSON 21.05
Differentiable rendering: the backward pass
Derive, implement and verify the gradient of a splatting renderer: reverse-mode chain rule, the back-to-front backward of alpha compositing that rebuilds T from the final transmittance, gradients through the 0.99 clamp, central-difference gradient checks, Adam with bias correction and per-group learning rates, L1 + D-SSIM, and adaptive density control.
Open lesson - LESSON 21.06
Compressing and streaming Gaussian splats
Shrink a 3DGS scene from ~240 bytes to 16 bytes per splat: fp16 with correct rounding, Morton-sorted chunks with per-chunk quantisation, smallest-three quaternions, log scales, SH pruning and k-means codebooks — then measure the damage with PSNR and stream it coarse-to-fine.
Open lesson
Production C++: build, test, debug, ship
- LESSON 22.01
Building real C++ projects: translation units, linking and CMake targets
How a multi-file C++ project becomes binaries: headers and the ODR, reading linker errors, static vs shared libraries, and target-based CMake — usage requirements, presets, packages and compile_commands.json.
Open lesson - LESSON 22.02
Testing a C++ project: CTest, fixtures and golden images
Test a real C++ library the way production teams do: CTest labels and fixtures, doctest, deterministic fixtures from a specified PRNG, golden images with documented tolerances, regression tests from observed failures, test seams and malformed input.
Open lesson - LESSON 22.03
Debugging failures: sanitizer reports, core dumps, minimal repros
Read ASan, LSan, UBSan and TSan reports frame by frame, debug a core dump with gdb, tell a lifetime bug from a concurrency bug, shrink the failure to a minimal reproduction and pin it with a regression test — then build a parser that triages sanitizer reports automatically.
Open lesson - LESSON 22.04
CI, reproducible builds and releases
Ship C++ like a team does: a GCC/Clang × Debug/ASan/TSan/Release matrix as a local script and a hosted-CI config, warnings as errors in CI only, reproducible builds, semantic versions from git describe, install rules, RPATH and a CPack tarball, and a release checklist.
Open lesson
Qt and Linux application integration
- LESSON 23.01
Qt object lifetime: parents, deleteLater and QPointer
Who deletes a QObject and when: parent/child trees, deleteLater and the event loop, QPointer and destroyed, connection lifetime with context objects, thread affinity, and Qt's implicitly shared containers.
Open lesson - LESSON 23.02
Qt models, QML and model tests
Write a QAbstractListModel that keeps every view in sync: the begin/end change protocol, the move-destination rule, precise dataChanged roles, invalid-index handling, QAbstractItemModelTester and QSignalSpy tests, and how the model reaches QML.
Open lesson - LESSON 23.03
Background work in a Qt application
Keep the UI thread responsive: QThread workers, QtConcurrent and std::jthread backends, queued delivery, cooperative cancellation, latest-wins request coalescing, generation counters and clean shutdown while work is in flight.
Open lesson - LESSON 23.04
Linux I/O, IPC and process lifecycle
The plumbing of a Linux service: RAII file descriptors, partial reads and writes, EINTR/EAGAIN, poll with deadlines, pipes and Unix sockets, message framing, backpressure and reconnects, signals for clean shutdown, child processes and systemd units.
Open lesson
C++ ↔ Python and GPU
- LESSON 24.01
C++ ↔ Python boundaries with pybind11
Put the hot loop in C++ and keep the research in Python: pybind11 modules over NumPy arrays (buffer protocol, dtype and shape checks, strides), ownership across the boundary (return value policies, keep_alive, capsules, zero-copy views), releasing the GIL, exception translation, and building the extension with CMake.
Open lesson - LESSON 24.02
GPU kernel basics (CUDA)
The CUDA execution model from the kernel's point of view: grids, blocks and warps, index math and bounds checks, coalesced global memory, shared-memory tiles and bank conflicts, __syncthreads rules, atomics, streams and launch errors — graded on a deterministic CPU kernel simulator.
Open lesson - LESSON 24.03
GPU correctness and honest benchmarks
Check GPU results against a CPU reference with abs/rel/ULP tolerances, time kernels honestly (cudaEvent, warm-up, sync, transfers, medians), profile with Nsight, and write reports that never overclaim.
Open lesson
RTOS on the Cortex-M4 (FreeRTOS)
- LESSON 25.01
Tasks, scheduling and queues (FreeRTOS)
FreeRTOS on a Cortex-M4: task states, preemptive priority scheduling and time slicing, the idle task, vTaskDelay vs xTaskDelayUntil, stack budgets with high-water marks, queues (copy semantics and passing ownership by pointer), timeouts, task notifications, and static vs dynamic allocation.
Open lesson - LESSON 25.02
Priority inversion, mutexes and deadlock
Why a high-priority FreeRTOS task can wait on a medium one: unbounded priority inversion, Mars Pathfinder, binary semaphores vs mutexes, priority inheritance and its limits, priority ceilings, recursive mutexes, deadlock and lock ordering — and a shared-bus guard with a deadline monitor and an ownership trace.
Open lesson - LESSON 25.03
From interrupt to task (deferred processing)
Deferred interrupt processing under FreeRTOS on the Cortex-M4: waking tasks from ISRs with task notifications, queues and stream buffers, portYIELD_FROM_ISR and the latency it saves, ISR priorities versus configMAX_SYSCALL_INTERRUPT_PRIORITY (and the assert you get when it's wrong), what an ISR may call, counting overruns, and stopping an ISR-fed task cleanly.
Open lesson - LESSON 25.04
Fault detection and recovery under an RTOS
Keeping FreeRTOS firmware alive when a task gets stuck: hardware and software watchdogs, heartbeats with deadlines, restarting a task with fresh state, xTaskAbortDelay, timeouts on every wait, stack-overflow checks and configASSERT, fault records that survive a reset, and fail-safe states.
Open lesson
Unix/Linux: files, descriptors & filesystem
- LESSON 26.01
Descriptors & open file descriptions
Own Linux descriptors in C++: move-only RAII, atomic close-on-exec duplication, shared offsets and status flags, independent descriptor flags and errno-safe cleanup.
Open lesson - LESSON 26.02
Syscalls, short I/O & positioned files
Handle errno, EINTR, short reads/writes and EOF; use pread/pwrite without disturbing shared offsets, reject Linux append-mode traps, and test error paths deterministically.
Open lesson - LESSON 26.03
Directories, inodes & relative path operations
Separate names, inodes and open handles; walk directory descriptors with openat, reject symlinks, understand unlink/rename, permissions and the limits of userspace path policies.
Open lesson
Unix/Linux: processes, memory & signals
- LESSON 27.01
Processes: fork, exec, pipes & wait
Launch a program without a shell, arrange inherited descriptors, distinguish exec failure from exit status, drain a pipe before waiting and reap every child.
Open lesson - LESSON 27.02
Virtual memory & mapped file windows
Map an unaligned file slice with page-aligned mmap, separate ownership from spans, transfer mappings safely, and understand MAP_PRIVATE, page faults and SIGBUS after truncation.
Open lesson - LESSON 27.03
Signals & descriptor-based notifications
Distinguish signal delivery from queued work; consume blocked signals with signalfd and aggregate wakeups with eventfd without allocating or logging in a signal handler.
Open lesson
Unix/Linux: event-driven networking & IPC
- LESSON 28.01
Nonblocking I/O & epoll readiness
Build a level-triggered readiness layer with 64-bit tokens, bounded nonblocking drains, buffered-data-plus-hangup handling, and explicit EAGAIN versus EOF semantics.
Open lesson - LESSON 28.02
TCP sockets, connection state & half-close
Bind a loopback listener to an ephemeral port, complete a nonblocking connect with SO_ERROR, accept safely, and distinguish TCP byte streams, EOF and half-close.
Open lesson - LESSON 28.03
Unix sockets & passing open descriptors
Transfer a kernel open-file reference with SCM_RIGHTS, parse ancillary messages, set close-on-exec at receipt, and close every installed descriptor on malformed/truncated messages.
Open lesson
RTOS: software timers & event coordination
CMSIS: Cortex-M Core & RTOS2 on FreeRTOS
- LESSON 30.01
CMSIS-Core: device headers, NVIC & intrinsics
Use Arm CMSIS-Core on the Cortex-M4: device configuration, logical NVIC priorities, nested PRIMASK guards, barriers and saturating intrinsics.
Open lesson - LESSON 30.02
CMSIS-RTOS2 on FreeRTOS: threads, queues & API contracts
Run the CMSIS-RTOS2 API on the real FreeRTOS kernel: byte-sized thread stacks, priorities, copied messages, bounded waits, flags and adapter limits.
Open lesson
Standard containers: contracts, bits & duplicate keys
- LESSON 31.01
Standard containers: identity, transfer & invalidation
Apply list splice, forward_list erasure, map node handles and borrowed array views; choose storage by ownership and stability guarantees.
Open lesson - LESSON 31.02
Packed booleans: vector<bool>, proxies & bitset
Distinguish bit proxies from boolean values, use fixed-width bit operations beyond 64 bits, and preserve snapshots, bounds and subset-sum semantics.
Open lesson - LESSON 31.03
Duplicate keys: ordered, hashed & flat containers
Use multimap/multiset and unordered multi variants, plus flat_set/flat_multiset/flat_multimap; preserve multiplicity, deterministic results and sorted invariants.
Open lesson
Shaped views & stable block storage
- LESSON 32.01
mdspan: shape, strides & borrowed multidimensional data
Use actual C++23 mdspan with right, left and padded layouts; validate backing spans and overflow, distinguish logical size from storage, and transpose safely.
Open lesson - LESSON 32.02
hive storage: stable entities with the reference implementation
Practice stable insertion and erasure using pinned plf::hive, with a consistent id index and lifetime checks. Native std::hive remains unavailable here.
Open lesson
C library: bytes, strings & characters
- LESSON 33.01
Byte buffers & memory functions
Validate byte ranges before calling memmove; distinguish overlap, byte counts and object representation from typed value operations.
Open lesson - LESSON 33.02
C strings, terminators & bounded adapters
Keep byte length, buffer capacity and NUL termination distinct; use memchr to inspect bounded storage and copy text without silent truncation.
Open lesson - LESSON 33.03
Character classification, locale & byte text
Use cctype with unsigned-byte values, trim C-locale whitespace, and separate byte-oriented case conversion from Unicode text processing.
Open lesson
C library: conversion, allocation & streams
- LESSON 34.01
Checked numeric conversion & errno
Combine strtol/strtod, end pointers, errno and destination bounds; reject incomplete tokens, embedded NUL, whitespace, overflow and nonfinite numbers.
Open lesson - LESSON 34.02
malloc, calloc, realloc & ownership
Own C-allocated byte storage, check size products before allocation, preserve the old block on realloc failure and release with the matching allocator.
Open lesson - LESSON 34.03
FILE streams, buffering & binary I/O
Use fread/fwrite counts, distinguish EOF from stream errors, and flush buffered output while keeping FILE ownership explicit.
Open lesson
C library: formatting, callbacks & time
- LESSON 35.01
Format strings, snprintf & bounded input
Match variadic format arguments exactly, interpret snprintf counts and truncation, and separate trusted formats from input data.
Open lesson - LESSON 35.02
qsort, bsearch & C callbacks
Sort trivially copyable records with an overflow-safe C comparator, then search by key without assuming stable order or a particular duplicate match.
Open lesson - LESSON 35.03
Calendar time, CPU clocks & formatting
Distinguish time_t, tm and clock_t; format validated calendar fields and convert CPU ticks without assuming a Unix epoch or wall-clock timing.
Open lesson
Core Guidelines: interfaces, expressions & enums
- LESSON 36.01
Core Guidelines: explicit, bounded interfaces
Design APIs that carry argument roles, bounds, ownership and failure policy; validate borrowed input before returning owned domain values.
Open lesson - LESSON 36.02
Core Guidelines: checked expressions and scoped enums
Initialize before use, validate arithmetic and conversions before evaluation, and represent enum domains with explicit checked boundaries.
Open lesson
Core Guidelines: class design & exception guarantees
- LESSON 37.01
Core Guidelines: polymorphic interfaces without slicing
Choose value types or abstract interfaces deliberately; prevent slicing, preserve dynamic types through clone, and copy owned operations safely.
Open lesson - LESSON 37.02
Core Guidelines: exception guarantees and commit points
State the basic, strong and no-throw guarantees; stage fallible work under RAII and commit without changing promised state on failure.
Open lesson
Binary & hex
- LESSON 38.01
Binary: bits, place values & unsigned words
Convert binary and decimal, distinguish a value from its spelling, and validate fixed-width unsigned words without overflowing or shifting by the type width.
Open lesson - LESSON 38.02
Hexadecimal: nibbles, bytes & byte order
Read and write hex bytes, convert four-bit groups, and decode explicit little- and big-endian values without confusing display order with memory order.
Open lesson
Signed encodings
- LESSON 39.01
One's complement: negative zero & end-around carry
Model one's-complement signed words explicitly: encode negatives by inverting within the width, preserve both zeros, and add with end-around carry.
Open lesson - LESSON 39.02
Two's complement: signed values, extension & overflow
Encode and decode two's-complement words, sign-extend them, and distinguish unsigned carry from signed overflow without executing C++ signed overflow.
Open lesson