Template

Learn C++

Learn C++ properly: the core language, how memory and types really work, the standard library, and enough modern C++ to write correct and efficient code without fighting the language.

This roadmap takes you from absolute beginner to writing robust, idiomatic, and high-performance modern C++ (C++17/C++20). The progression emphasizes hands-on software construction at every stage: you will move from imperative syntax and memory layout to RAII, move semantics, template metaprogramming, and concurrent systems programming. At roughly 10 hours per week across approximately 30-35 weeks, you will build concrete command-line utilities, custom data structures, memory allocators, and multithreaded engines, leaving you able to architect, debug, and optimize complex C++ codebases without relying on legacy idioms or undefined behavior.

By the end: You will be able to design, write, compile, and debug idiomatic, performant modern C++ applications leveraging RAII, custom templates with concepts, zero-overhead abstractions, and thread-safe concurrency models.

Starting levelBeginnerStyleBuilding things
10h / week10 phases30 tasks~143h total

This is the map — make this roadmap yours

It shows what this journey generally looks like. Tell Kaidoro your version of the goal and it builds the plan around where you are actually starting, what to do first, the hours you really have, and what you have already finished.

1

Environment, Toolchain, and Imperative Syntax

Establish a modern compiler workflow and master basic control flow, fundamental data types, and the C++ translation unit model.

  • Install modern C++ toolchain and configure CMake
    ~3hBuild

    Understanding the compiler, linker, and build system separation is necessary before writing any non-trivial C++ code.

    You'll learn

    • CMake — the industry-standard meta-build tool that generates platform native makefiles or Ninja files
    • Compiler flags — command-line arguments like -Wall and -Wextra that enforce strict code hygiene
    • clangd — the language server protocol daemon providing code completion and error diagnostics

    Set up a modern C++ compiler (Clang or GCC) supporting C++20 and initialize a project using CMake. You will verify your environment by compiling a multi-file hello-world program from the terminal.

    Done when: running cmake --build build compiles and outputs your greeting program with zero warnings.

    How to work through it

    1. Install GCC/Clang, CMake, and a modern editor with clangd support
    2. Write a simple CMakeLists.txt targeting C++20 with strict warning flags (-Wall -Wextra -Wpedantic)
    3. Build and run your executable from the command line
  • Build a modular CLI unit converter
    ~4hBuild1 resource

    Header and source separation is the structural foundation of all multi-file C++ programs.

    You'll learn

    • Header guards — preprocessor directives (#pragma once) preventing duplicate symbol definitions
    • std::cin / std::cout — standard library character streams for terminal input and output
    • Translation units — individual source files compiled independently into object files before linking

    Implement an interactive command-line converter supporting length, temperature, and currency conversions. Split the declarations into header files (.hpp) and definitions into implementation files (.cpp) to practice the compilation model.

    Done when: the program compiles with headers properly guarded, handles invalid user input cleanly, and passes manual test conversions.

    How to work through it

    1. Create separate header files for each converter category using `#pragma once`
    2. Implement function logic in matching .cpp files
    3. Implement an interactive loop in main.cpp reading user selections via std::cin and std::cout
    4. Add validation loops to re-prompt on invalid floating-point inputs
  • Build a terminal-based Number Guessing Game with stats tracking
    ~4hBuild1 resource

    This cements control flow and basic state management in a single self-contained project.

    You'll learn

    • std::mt19937 — standard pseudo-random number generator producing high-quality random values
    • std::uniform_int_distribution — maps raw random engine output onto a bounded integer range
    • Stream state flags — internal stream condition bits checked via .fail() and reset with .clear()

    Create a replayable guessing game featuring random number generation, input validation, switch statements, and loop constructs. Maintain and print game statistics such as win streak, average attempts, and best round.

    Done when: you can play 5 consecutive rounds without crashes, handle non-integer input gracefully, and see accurate summary statistics upon exit.

    How to work through it

    1. Use `<random>` to seed a standard Mersenne Twister engine (`std::mt19937`)
    2. Write the game loop tracking attempt counts and user guesses
    3. Check and clear stream error states (`std::cin.clear()` and `std::cin.ignore()`) when parsing fails
    4. Print formatted post-game statistics upon user quit
2

Types, Memory Layout, and Function Semantics

Explore variable lifetimes, scope, fundamental types, enums, structs, and pass-by-value vs. pass-by-reference mechanics.

  • Inspect memory sizes and alignment of primitive and composite types
    ~3hPractice

    Understanding binary memory layout is critical for writing cache-friendly and space-efficient systems code.

    You'll learn

    • sizeof / alignof — compile-time operators returning byte size and byte alignment requirements
    • Struct padding — invisible alignment bytes inserted by compilers to satisfy CPU word alignment
    • Fixed-width integer types — explicit size types from <cstdint> such as int32_t and uint64_t

    Write a diagnostics tool that outputs sizeof() and alignof() for primitive types (int, double, char, bool) and custom structs with different field orderings. Observe how compiler padding affects memory footprint.

    Done when: your diagnostic program prints a tabular layout comparison demonstrating the impact of struct member ordering on padding bytes.

    How to work through it

    1. Define structs with identical member types arranged in descending vs mixed size order
    2. Print `sizeof` and `alignof` along with member offsets using the `offsetof` macro
    3. Analyze and document the padding bytes inserted by the compiler
  • Implement value vs reference function utilities
    ~4hPractice1 resource

    References are ubiquitous in modern C++; knowing when to copy and when to alias prevents subtle bugs and expensive allocations.

    You'll learn

    • Pass-by-const-reference — avoids copying large objects while guaranteeing immutability inside the callee
    • Lvalue references — aliases to existing memory locations denoted with &
    • const correctness — the practice of enforcing compile-time read-only guarantees on variables and parameters

    Write mathematical and string modification utilities that demonstrate pass-by-value, pass-by-const-reference, and pass-by-mutable-reference. Compare performance and safety trade-offs when passing large structures.

    Done when: all utility functions execute as expected, demonstrating in-place mutation where required and zero-copy read access with const &.

    How to work through it

    1. Implement a function that swaps two custom structs via mutable references
    2. Implement a function that takes a read-only large struct by `const&` and computes an aggregate score
    3. Implement pass-by-value variations and step through using a debugger to observe copy behavior
  • Build an in-memory Student Gradebook system
    ~5hBuild1 resource

    Combines structured data types, reference passing, and container manipulation into a functioning domain model.

    You'll learn

    • enum class — strongly-typed, scoped enumerations that prevent accidental implicit conversions to integers
    • std::vector — dynamically sized contiguous memory buffer for homogeneous elements
    • Range-based for loop — clean syntax for iterating over collections (`for (const auto& item : items)`)

    Build a command-line student record manager utilizing scoped enums (enum class), structs, and std::vector. Implement filtering, GPA calculations, and formatted transcript generation.

    Done when: the program can add, update, calculate averages, and print sorted student report cards using strongly typed enums and structs.

    How to work through it

    1. Define an `enum class GradeLetter` and a `struct StudentRecord`
    2. Implement functions to calculate GPA by passing records by const reference
    3. Provide sorting and lookup functions operating over a collection of records
    4. Render a clean tabular summary in the console
3

Raw Pointers, Memory Model, and Dynamic Allocation

Directly manipulate memory addresses, trace the stack vs. the heap, understand pointer arithmetic, and debug memory corruption using sanitizers.

  • Experiment with pointer arithmetic and memory exploration
    ~4hPractice1 resource

    Demystifying pointers is essential to understanding what the CPU and OS are doing under the hood.

    You'll learn

    • Pointer dereferencing — accessing or modifying the value stored at a specific memory address via `*`
    • Pointer arithmetic — scaling address offsets based on the byte size of the underlying type
    • Endianness — the order in which bytes of multi-byte data types are stored in computer memory

    Write programs that inspect memory addresses using raw pointers, traverse contiguous arrays via pointer increments, and print byte-by-byte hex dumps of arbitrary objects in memory.

    Done when: your utility prints exact hexadecimal byte representations and addresses for various variable types on the stack.

    How to work through it

    1. Declare stack arrays and print element memory addresses to observe memory contiguity
    2. Re-implement array indexing using pure pointer arithmetic `*(ptr + offset)`
    3. Cast object pointers to `const uint8_t*` to inspect byte-level endianness
  • Build a dynamically resizing integer array from scratch
    ~5hBuild1 resource

    Building a dynamic array manually teaches you what `std::vector` abstracts away and why manual management is prone to errors.

    You'll learn

    • new[] and delete[] — raw operators for heap memory allocation and deallocation in C++
    • AddressSanitizer (ASan) — compiler instrumentation tool for detecting out-of-bounds access and memory leaks
    • Heap fragmentation and reallocation — copying overhead and pointer invalidation caused by buffer expansion

    Implement a dynamically allocated array using raw new[] and delete[]. Manage growth by allocating a new buffer with double capacity, copying elements over, and freeing old memory.

    Done when: the dynamic array can perform 10,000 append operations without memory leaks when checked under AddressSanitizer or Valgrind.

    How to work through it

    1. Create a struct holding data pointer, size, and capacity
    2. Implement `push_back` with dynamic buffer reallocation and element copying
    3. Implement cleanup functions that invoke `delete[]`
    4. Compile with `-fsanitize=address` to verify zero leaks and zero use-after-free errors
  • Build a raw-pointer singly linked list with full CRUD
    ~5hBuild1 resource

    Linked lists force rigorous pointer manipulation and edge-case handling around null pointers and resource freeing.

    You'll learn

    • nullptr — the type-safe null pointer literal introduced in modern C++
    • Memory leak — heap memory that was allocated but never freed before dropping the pointer
    • Dangling pointer — a pointer referencing a memory address that has already been deallocated

    Construct a singly linked list managing its own nodes dynamically on the heap. Provide insertion, deletion, value search, reversing, and complete destruction.

    Done when: the linked list passes an automated test suite verifying node insertion at head/tail, node removal, list reversal, and clean leak-free destruction.

    How to work through it

    1. Define a `Node` struct containing data and a `Node* next` pointer
    2. Implement `push_front`, `push_back`, `erase(value)`, and `reverse` functions
    3. Implement a recursive or iterative `clear()` function that deletes every node
    4. Test thoroughly with an empty list, single element list, and multi-element list
4

Object-Oriented Programming and RAII

Learn encapsulation, constructors, destructors, class invariants, inheritance, runtime polymorphism with virtual tables, and the core idiom of RAII.

  • Implement an RAII File Handler wrapper
    ~4hBuild1 resource

    RAII (Resource Acquisition Is Initialization) is the single most important architectural pattern in C++.

    You'll learn

    • RAII — tying resource lifecycle strictly to object lifetime via constructors and destructors
    • Explicit constructor — preventing unintended implicit conversions by marking single-argument constructors `explicit`
    • = delete — modern C++ syntax to explicitly disallow compiler-generated special member functions

    Create a C++ class that wraps a C-style file handle (FILE*). Ensure the resource is opened in the constructor and automatically closed in the destructor, guaranteeing exception safety and no leaked file descriptors.

    Done when: opening and writing to files through your RAII class never leaks open file descriptors, even when functions exit early or throw errors.

    How to work through it

    1. Write a class `FileHandle` taking a file path and mode in its constructor
    2. Call `fclose` inside the destructor `~FileHandle()` if the handle is valid
    3. Disable copying by deleting copy constructor and copy assignment operator
    4. Demonstrate deterministic cleanup when instances go out of scope
  • Build an extensible Shape Hierarchy with virtual functions
    ~5hBuild1 resource

    Polymorphism and virtual dispatch are core object-oriented mechanisms for building extensible domain hierarchies.

    You'll learn

    • vtable and vptr — the compiler-generated lookup table and pointer used for dynamic dispatch
    • override keyword — compile-time check ensuring a member function truly overrides a base class virtual function
    • Virtual destructor — ensures that deleting an object through a base pointer invokes the correct derived destructor

    Create an abstract base class Shape with pure virtual methods for area(), perimeter(), and render(). Derive concrete classes (Circle, Rectangle, Polygon) and manage them polymorphically.

    Done when: a collection of Shape* base pointers computes composite areas and renders each shape correctly through virtual dynamic dispatch.

    How to work through it

    1. Define `Shape` with pure virtual functions (`= 0`) and a virtual destructor
    2. Implement derived classes with `override` keyword on all overridden virtual methods
    3. Store pointers to shapes in an array and iterate to invoke polymorphic behavior
    4. Observe virtual method table (vtable) dispatch using a debugger
  • Build a Turn-Based RPG Combat Simulator using OOP
    ~6hBuild1 resource

    This consolidates class design, inheritance, encapsulation, and lifecycle management into a complete interactive project.

    You'll learn

    • Access specifiers — `private`, `protected`, `public` control over member accessibility
    • Class invariants — conditions that must remain true for an object to stay in a valid state
    • Dynamic casting — `dynamic_cast<T*>` for safe runtime downcasting within polymorphic hierarchies

    Design an object-oriented combat simulator featuring characters, equipment, effects, and combat actions. Utilize abstract base classes for abilities, encapsulation for health/stats invariants, and polymorphism for status effects.

    Done when: the simulator can run automated battle rounds between different character subclasses with all status effects and combat calculations executing correctly.

    How to work through it

    1. Design an abstract `Entity` base class and derive `Warrior`, `Mage`, and `Rogue`
    2. Implement a polymorphic `StatusEffect` system (e.g., Poison, Shield) applied each turn
    3. Maintain strict private data encapsulation, validating mutations via public methods
    4. Simulate turn order and display dynamic combat logs in the terminal
5

Move Semantics, Operator Overloading, and Rule of 0/3/5

Understand value categories (lvalues vs. rvalues), write custom copy/move constructors, overload operators idiomatically, and master the Rule of Five.

  • Build a custom String class with the Rule of Five
    ~5hBuild1 resource

    Move semantics is the foundation of high-performance modern C++, allowing zero-cost transfers of heavy heap allocations.

    You'll learn

    • Rvalue references — references to temporary objects denoted with `&&`
    • std::move — an unconditional cast from an lvalue to an rvalue expression enabling move constructors
    • Rule of Five — if a class declares a custom destructor or copy/move operation, it must declare all five
    • Copy-and-swap idiom — an elegant technique to implement strong exception-safe assignment operators

    Write a MyString class managing dynamic character buffers. Implement the copy constructor, copy assignment operator, move constructor, move assignment operator, and destructor. Measure performance differences between deep copies and move operations.

    Done when: MyString passes unit tests verifying deep copying on lvalue assignment, pointer pilfering on std::move, self-assignment safety, and zero leaks.

    How to work through it

    1. Implement constructor allocating heap buffer and destructor releasing it
    2. Implement copy constructor and copy assignment using the copy-and-swap idiom
    3. Implement move constructor and move assignment operator transferring raw pointer ownership and nulling the source
    4. Benchmark creating and vector-pushing 100,000 strings with and without move semantics
  • Implement an idiomatic BigInt / Vector2D class with operator overloading
    ~4hPractice1 resource

    Operator overloading makes custom types behave naturally like built-in primitives, improving expressiveness and readability.

    You'll learn

    • Three-way comparison (spaceship operator <=>) — C++20 operator that synthesizes all six relational comparisons
    • Friend functions — functions granted access to private members, standard for binary stream operators
    • Const member functions — member functions marked `const` guaranteeing they do not mutate instance state

    Implement a 2D Vector or mathematical BigInt class with fully overloaded operators: arithmetic (+, -, *), compound assignment (+=, -=), comparison (<=>, ==), stream output (<<), and subscripting ([]).

    Done when: all mathematical expressions evaluate accurately, chained operations (a + b * c) adhere to standard precedence, and formatted output displays cleanly via std::cout << vec.

    How to work through it

    1. Implement member compound assignment operators (`+=`, `-=`)
    2. Implement non-member binary arithmetic operators (`+`, `-`) reusing compound assignments
    3. Implement C++20 three-way comparison operator (`operator<=>`) for default ordering
    4. Overload `operator<<` for standard stream output
  • Build a custom Matrix container implementing Rule of Five and math operators
    ~5hBuild1 resource

    Synthesizes modern memory lifecycle management and expressive operator overloading into a robust data structure.

    You'll learn

    • Contiguous 1D backing storage — flattening 2D arrays to maximize CPU cache line utilization
    • Rule of Zero — designing classes using standard components so no custom destructors or copy/move operations are needed
    • Exception guarantees — writing operations that provide basic or strong exception safety

    Create a dynamically allocated 2D Matrix class combining dynamic memory management, full Rule of Five compliance, bracket indexing operator()(row, col), matrix addition, and multiplication.

    Done when: the matrix class allocates memory in a contiguous block, multiplies matrices of arbitrary dimensions correctly, and moves temporary buffers without copying.

    How to work through it

    1. Store matrix elements in a single contiguous 1D array (`rows * cols`) for cache locality
    2. Implement constructor, copy/move operations, and destructor satisfying Rule of Five
    3. Implement `operator()(size_t r, size_t c)` for 2D indexing
    4. Implement matrix multiplication with boundary dimension checks
6

Modern Smart Pointers and Standard Library Containers

Replace manual memory management with `std::unique_ptr`, `std::shared_ptr`, and `std::weak_ptr`, and master standard associative and sequential containers.

  • Refactor a raw-pointer graph into smart pointers
    ~4hBuild1 resource

    Smart pointers express clear ownership semantics in modern C++, eliminating manual `delete` calls while preventing memory leaks.

    You'll learn

    • std::unique_ptr — zero-overhead move-only smart pointer ensuring exclusive ownership
    • std::shared_ptr — reference-counted smart pointer enabling shared ownership across multiple owners
    • std::weak_ptr — non-owning observer pointer preventing reference counting memory cycles
    • std::make_unique / std::make_shared — factory functions providing exception safety and optimized allocation

    Construct a graph data structure where nodes own sub-elements via std::unique_ptr, shared connections via std::shared_ptr, and back-references/cycles using std::weak_ptr to avoid circular memory leaks.

    Done when: circular graph cycles are constructed and destroyed without memory leaks, proven by running under AddressSanitizer.

    How to work through it

    1. Model nodes and edges using `std::unique_ptr` for exclusive ownership
    2. Implement shared references with `std::shared_ptr` and `std::make_shared`
    3. Break potential reference cycles using `std::weak_ptr` and test `.lock()` access
    4. Verify destruction orders using debug destructor log outputs
  • Benchmark Standard Library containers (vector, deque, list, map, unordered_map)
    ~5hPractice1 resource

    Understanding underlying container mechanics (contiguous buffers, balanced BSTs, hash buckets) allows you to choose the right data structure for performance.

    You'll learn

    • std::unordered_map — hash table container providing O(1) average lookup time
    • std::map — red-black self-balancing binary search tree container providing O(log N) ordered traversal
    • Cache locality — CPU hardware caching efficiency favoring contiguous memory like std::vector over linked nodes

    Write a benchmarking tool that evaluates random insertion, sequential traversal, and key-based lookup across std::vector, std::deque, std::list, std::map, and std::unordered_map across 1,000 to 500,000 elements.

    Done when: the benchmark produces an empirical performance report comparing CPU cache locality benefits of std::vector against node-based containers.

    How to work through it

    1. Use `<chrono>` high-resolution clocks to time insertions, lookups, and deletions
    2. Test contiguous containers (`std::vector`) vs node containers (`std::list`, `std::set`)
    3. Test sorted associative containers (`std::map`) vs hash tables (`std::unordered_map`)
    4. Tabulate and analyze execution time and memory scaling curves
  • Build an in-memory Key-Value Cache with LRU eviction
    ~5hBuild1 resource

    Combines multiple STL containers and ownership semantics to build an industry-standard data structure.

    You'll learn

    • std::list::splice — transfers elements between lists in O(1) time without reallocating nodes
    • Iterator validity — understanding which container operations invalidate iterators and which preserve them
    • std::optional — return type representing either a valid object or no value (`std::nullopt`)

    Build an in-memory Least Recently Used (LRU) Cache utilizing std::unordered_map for O(1) lookups and std::list for O(1) eviction tracking, managed entirely via modern smart pointers.

    Done when: the cache stores key-value pairs up to a fixed capacity, evicts the oldest unused item upon overflow, and passes comprehensive unit tests for get, put, and capacity bounds.

    How to work through it

    1. Maintain a `std::list` of key-value pairs representing access recency
    2. Maintain a `std::unordered_map` mapping keys to list iterators for O(1) access
    3. Implement `get(key)` moving accessed items to the front of the list
    4. Implement `put(key, value)` with automatic eviction of the least recently used element when over capacity
7

Templates, Concepts, and Compile-Time Metaprogramming

Master generic programming: function templates, class templates, template specialization, compile-time evaluation with `constexpr`/`consteval`, and C++20 Concepts.

  • Build a generic dynamic stack and ring buffer template
    ~5hBuild1 resource

    Templates enable writing type-agnostic, zero-overhead reusable abstractions.

    You'll learn

    • Class templates — blueprints for generating type-parameterized classes at compile-time
    • Non-type template parameters (NTTP) — passing values (like integers or sizes) as template arguments
    • Perfect forwarding — preserving lvalue/rvalue category using `T&&` forwarding references and `std::forward`

    Write a generic Stack<T> and fixed-capacity CircularBuffer<T, N> using class templates and non-type template parameters (NTTP). Support generic types with full move semantics and emplace mechanics.

    Done when: the circular buffer correctly stores arbitrary types (primitives, custom classes, move-only smart pointers) with compile-time bounded capacity.

    How to work through it

    1. Write a class template parameterized on `typename T` and `size_t Capacity`
    2. Implement `emplace` using variadic templates and `std::forward`
    3. Provide copy and move constructors enabled only when `T` supports them
    4. Test with move-only types such as `std::unique_ptr<int>`
  • Constrain template functions using C++20 Concepts and Constraints
    ~4hPractice1 resource

    C++20 Concepts make generic programming readable, safe, and compile-time verifiable.

    You'll learn

    • C++20 Concepts — named compile-time predicates that constrain template arguments
    • requires expression — syntax for checking whether arbitrary expressions compile successfully
    • Type traits — standard meta-functions from `<type_traits>` for compile-time type inspection

    Refactor generic utilities using C++20 concept and requires clauses. Define custom concepts like Numeric, Printable, and Serializable, replacing confusing template compiler errors with clear constraint violations.

    Done when: passing incompatible types to constrained functions produces direct compiler concept errors rather than cryptic 50-line deep template instantiation traces.

    How to work through it

    1. Define a custom `concept Numeric = std::integral<T> || std::floating_point<T>`
    2. Define a concept checking whether a type supports serialization via stream operator `<<`
    3. Apply `requires` clauses to function templates and evaluate compile-time error clarity
    4. Implement constrained template function overloads
  • Build a compile-time JSON / Configuration parser with constexpr
    ~5hBuild1 resource

    Compile-time programming shifts work from runtime to compilation, improving performance and finding errors before the program ever runs.

    You'll learn

    • constexpr — keyword specifying that a function or variable can be computed at compile time
    • consteval — immediate functions that are guaranteed to execute only at compile time
    • static_assert — compile-time assertion that halts the compiler if a boolean condition evaluates to false

    Create a string/config parser that runs entirely at compile-time using constexpr and consteval. Verify that valid configurations compute values and tables during compilation with zero runtime overhead.

    Done when: configuration strings are parsed into structured data tested via static_assert, generating zero assembly instructions at runtime for validation.

    How to work through it

    1. Write `constexpr` string view parsing helper functions
    2. Parse key-value integer configuration pairs into a compile-time lookup table
    3. Use `static_assert` to validate correct parsing and deliberately trigger build errors on invalid input
    4. Inspect generated assembly on Compiler Explorer (Godbolt) to verify zero runtime parsing cost
8

Modern Algorithms, Iterators, and C++20 Ranges

Learn to write expressive, loop-free code using standard algorithms, custom iterator design, lambda expressions, and composable C++20 Ranges pipelines.

  • Replace raw loops with standard algorithms and lambdas
    ~4hPractice1 resource

    The standard algorithms library provides tested, optimized, and intention-revealing operations.

    You'll learn

    • Lambda expressions — anonymous function objects defined in-place with custom capture semantics
    • std::transform / std::accumulate — fundamental map and fold operations of the C++ standard library
    • Erase-remove idiom — standard technique for removing matching elements from dynamic containers before C++20 `std::erase`

    Refactor a data processing pipeline by replacing raw for and while loops with <algorithm> functions (std::transform, std::accumulate, std::all_of, std::partition, std::sort) paired with capturing lambda expressions.

    Done when: the refactored data pipeline passes all functional tests while containing zero manual loop index variables or raw iteration loops.

    How to work through it

    1. Replace filtering loops with `std::copy_if` and `std::remove_if`
    2. Use `std::transform` and `std::reduce` for mapping and aggregation
    3. Utilize lambda capture lists (`[&]`, `[=]`, `[val = std::move(p)]`) effectively
    4. Sort complex structs using custom projection lambdas
  • Build a custom input/forward Iterator for a tree structure
    ~5hBuild1 resource

    Iterators are the glue between data structures and algorithms in the C++ standard library.

    You'll learn

    • Iterator concepts — standard requirements defining forward, bidirectional, and random access iterators
    • begin() / end() conventions — defining half-open ranges `[begin, end)` standard across all C++ containers
    • ADL (Argument-Dependent Lookup) — compiler lookup mechanism for finding non-member `begin()`/`end()` functions

    Implement a custom bidirectional or forward iterator conforming to standard C++ iterator categories for a binary search tree. Enable standard range-based for loops and standard algorithms to traverse your tree naturally.

    Done when: you can execute for (int val : my_tree) and run std::find directly across your custom tree data structure.

    How to work through it

    1. Define nested `iterator` struct with `iterator_category`, `value_type`, `difference_type`, and pointer/reference aliases
    2. Implement `operator*`, `operator->`, prefix/postfix `operator++`, and `operator==`
    3. Provide `begin()` and `end()` member functions on the tree class
    4. Pass the tree to standard algorithms like `std::count_if`
  • Build a log analytics pipeline using C++20 Ranges and Views
    ~5hBuild1 resource

    C++20 Ranges modernize C++ by allowing declarative, non-owning, lazily-evaluated data transformation pipelines.

    You'll learn

    • std::views — non-owning range adaptors that perform lazy transformations
    • std::string_view — non-owning, lightweight view into a contiguous sequence of characters
    • Pipeline operator (|) — syntax for chaining ranges adaptors cleanly

    Build a server log analysis tool utilizing std::ranges and composable views (std::views::filter, std::views::transform, std::views::take). Chain transformations lazily without intermediate container allocations.

    Done when: a chained ranges pipeline parses raw log lines, filters 4xx/5xx status codes, extracts IP addresses, and produces top-hit summaries using zero temporary vector allocations.

    How to work through it

    1. Read log files as a stream of `std::string_view`
    2. Construct a processing pipeline using pipe syntax (`| std::views::filter(...) | std::views::transform(...)`)
    3. Process results lazily without creating intermediary vectors
    4. Compare pipeline readability and memory usage against traditional loop-based parsing
9

Concurrency, Multithreading, and Memory Model

Write safe concurrent programs using threads, mutexes, condition variables, atomic operations, and lock-free primitives.

  • Build a thread-safe ThreadPool executor
    ~6hBuild1 resource

    Worker thread pools are the standard concurrency pattern in servers, game engines, and numerical computing.

    You'll learn

    • std::jthread / std::thread — standard primitives representing OS execution threads (with cooperative cancellation in C++20)
    • std::mutex & std::scoped_lock — RAII locking mechanisms preventing race conditions on shared data
    • std::condition_variable — synchronization primitive enabling threads to sleep until signaled by another thread
    • ThreadSanitizer (TSan) — compiler sanitizer detecting data races and race conditions at runtime

    Implement a multithreaded worker pool that manages a queue of arbitrary tasks (std::function<void()>). Synchronize workers with std::mutex and std::condition_variable, supporting graceful shutdown.

    Done when: the thread pool can execute 50,000 asynchronous tasks across 8 hardware threads, shut down cleanly without deadlocks, and pass ThreadSanitizer checks.

    How to work through it

    1. Spawn worker threads that loop waiting on a shared work queue
    2. Protect the task queue with `std::mutex` and `std::unique_lock`
    3. Signal waiting threads when work arrives via `std::condition_variable::notify_one`
    4. Implement a destructor that signals completion, joins all worker threads, and releases resources
  • Implement an asynchronous MapReduce framework with std::future
    ~5hBuild

    Task-based parallelism simplifies concurrent workflows without manual thread lifecycle management.

    You'll learn

    • std::async — executes a function asynchronously and returns a std::future containing the eventual result
    • std::future / std::promise — mechanism for transferring values or exceptions between asynchronous threads
    • std::thread::hardware_concurrency — queries the number of concurrent hardware execution units supported by the CPU

    Write a parallel map-reduce processing framework using std::async, std::future, and std::promise. Process large datasets by partitioning work across available CPU cores and reducing results asynchronously.

    Done when: the async map-reduce framework counts word frequencies across multiple text files concurrently, showing near-linear speedup compared to single-threaded execution.

    How to work through it

    1. Partition input chunks across available hardware concurrency (`std::thread::hardware_concurrency`)
    2. Dispatch worker tasks via `std::async(std::launch::async, ...)`
    3. Collect and combine results using `future.get()`
    4. Benchmark and measure multi-core CPU utilization scaling
  • Build a lock-free Single-Producer Single-Consumer (SPSC) Queue
    ~6hBuild1 resource

    Mastering the C++ memory model and atomic synchronization unlocks ultra-low-latency systems programming.

    You'll learn

    • std::atomic — provides lock-free atomic operations guaranteeing freedom from data races
    • Memory orders — memory synchronization semantics (relaxed, acquire, release, seq_cst) controlling CPU instruction reordering
    • False sharing — performance degradation caused by multiple threads updating atomic variables on the same CPU cache line

    Construct a bounded lock-free FIFO queue using std::atomic, memory orders (acquire/release), and circular buffer indexing. Validate high-throughput message passing without locks.

    Done when: a dedicated producer thread sends 10,000,000 messages to a consumer thread with zero locks, zero dropped messages, and no data races under ThreadSanitizer.

    How to work through it

    1. Create a ring buffer with atomic head and tail indices
    2. Use `std::memory_order_release` when publishing written items
    3. Use `std::memory_order_acquire` when reading published items
    4. Verify thread safety and benchmark latency against a mutex-based queue
10

Performance Profiling, Sanitizers, and Capstone Project

Profile code with modern performance tools, optimize hot paths, manage custom memory allocations, and build a complete, high-performance C++ systems application.

  • Build a custom Fixed-Size Block Memory Allocator
    ~5hBuild

    Custom allocators eliminate heap contention, prevent fragmentation, and are widely used in high-frequency trading and game engines.

    You'll learn

    • Free-list allocator — tracking available memory blocks by embedding pointers inside unused memory chunks
    • Placement new — constructing an object at a pre-allocated raw memory address (`new (address) Type(...)`)
    • std::pmr (Polymorphic Memory Resources) — modern standard library mechanism for supplying custom allocators to containers

    Write a custom pool/arena allocator that pre-allocates a large contiguous memory chunk and serves fixed-size object allocations in O(1) time using a free-list, bypassing global heap allocation overhead.

    Done when: allocating 1,000,000 small objects via your custom allocator is at least 3x faster than default new/delete calls.

    How to work through it

    1. Pre-allocate a contiguous memory arena of `N * BlockSize` bytes
    2. Maintain an in-place linked list of free blocks within the unused arena memory
    3. Implement `allocate()` popping from the free list and `deallocate()` returning blocks to the list
    4. Benchmark allocation speed against global `malloc` / `operator new`
  • Profile and optimize an image/matrix processing engine
    ~5hPractice1 resource

    Profiling guided optimization prevents premature optimization and teaches how hardware actually executes your code.

    You'll learn

    • CPU cache line — 64-byte chunks loaded into L1/L2/L3 caches; accessing memory sequentially maximizes cache hits
    • SIMD (Single Instruction Multiple Data) — hardware instructions processing multiple data elements in a single CPU cycle
    • Compiler Explorer (Godbolt) — interactive tool to inspect compiler optimization output across different flags

    Take a compute-heavy image filtering program, profile CPU bottlenecks using tools like perf or Valgrind Callgrind, identify cache misses, and optimize the hot loops with SIMD vectorization and cache-aware tiling.

    Done when: CPU profiling confirms a measurable performance speedup of at least 4x achieved through cache alignment and loop transformations.

    How to work through it

    1. Profile the unoptimized code using `perf record` and `perf report`
    2. Identify cache misses and branch mispredictions
    3. Refactor loops for cache line locality (tiling/blocking) and enable compiler auto-vectorization flags (`-O3 -march=native`)
    4. Document the before-and-after profiling metrics
  • Build an Async HTTP/TCP Key-Value Store (Capstone Project)
    ~8hBuild1 resource

    This capstone integrates every major facet of C++: systems I/O, concurrency, memory management, templates, RAII, and modern language features into a production-grade project.

    You'll learn

    • Systems architecture — combining concurrency, memory management, and networking into a cohesive engine
    • Undefined Behavior Sanitizer (UBSan) — compiler tool that flags signed integer overflows, alignment issues, and null pointer dereferences
    • Production code standards — building self-contained CMake projects with tests, sanitizers, and clean abstractions

    Design and build a complete asynchronous key-value database server from scratch. Incorporate RAII network sockets, a multithreaded thread pool, custom memory allocation, an in-memory LRU cache, C++20 Concepts, and automated unit testing.

    Done when: the server handles concurrent TCP client connections, parses commands (SET, GET, DEL, STATS), persists snapshots to disk, and runs clean with zero warnings under ASan, TSan, and UBSan.

    How to work through it

    1. Implement RAII wrappers for network sockets and file descriptors
    2. Integrate your ThreadPool to handle client connections concurrently
    3. Use your LRU cache and custom memory allocator for fast in-memory key storage
    4. Write a robust command parser using C++20 ranges and string_views
    5. Enforce zero memory leaks and data races across comprehensive automated integration tests

How the plan fits together

10 phases in 10 stages. Anything on the same row can be worked on at the same time.

An arrow points from a phase to the work it unlocks: before starting any phase, every phase with an arrow into it has to be finished first.

STARTSTAGE 2STAGE 3STAGE 4STAGE 5STAGE 6STAGE 7STAGE 8STAGE 9STAGE 101Environment, Toolchain,and Imperative Syntax3 tasks · ~11h2Types, Memory Layout, andFunction Semantics3 tasks · ~12h3Raw Pointers, MemoryModel, and DynamicAllocation3 tasks · ~14h4Object-OrientedProgramming and RAII3 tasks · ~15h5Move Semantics, OperatorOverloading, and Rule of0/3/53 tasks · ~14h6Modern Smart Pointers andStandard LibraryContainers3 tasks · ~14h7Templates, Concepts, andCompile-TimeMetaprogramming3 tasks · ~14h8Modern Algorithms,Iterators, and C++20Ranges3 tasks · ~14h9Concurrency,Multithreading, and MemoryModel3 tasks · ~17h10Performance Profiling,Sanitizers, and CapstoneProject3 tasks · ~18h

Resources

15 in this plan's library, beyond the links on individual tasks.

Tutorials & Reference Documentation

Core references, documentation, and tutorials.

  • C++ Concurrency in Action (2nd Edition)

    Use this definitive guide to master multithreading, synchronisation primitives, lock-free programming, and the C++ atomic memory model.

    manning.com · Manning Publications (Anthony Williams) · Book · ~$49.99 · Advanced

  • C++ Core Guidelines

    Use this set of modern best practices to understand ownership models, RAII patterns, and safe interface design.

    isocpp.github.io · Standard C++ Foundation (Bjarne Stroustrup & Herb Sutter) · Style & Best Practices Guide · Free · Intermediate to Advanced

  • C++ Templates: The Complete Guide (2nd Edition)

    The authoritative resource for mastering template metaprogramming, template specialization, and compile-time evaluation.

    Addison-Wesley Professional · Book · ~$55 · Advanced

  • Compiler Explorer (Godbolt)

    Use this online tool to inspect compiler-generated assembly in real time and evaluate abstraction costs across compiler versions.

    godbolt.org · Matt Godbolt · Web Application / Tool · Free · Intermediate

  • Cpplang Slack Workspace

    Use this large real-time chat platform to ask questions in channels dedicated to beginners, language evolution, and ecosystem tooling.

    cppalliance.org · The C++ Alliance · Chat Community · Free · All levels

  • cppreference.com

    Use this community-standard reference to look up exact type signatures, algorithmic complexities, and standard library behavior across modern C++ standards.

    en.cppreference.com · C++ Community / P. P. F. Czapiewski et al. · Reference Documentation · Free · Intermediate to Advanced

  • Effective Modern C++

    The definitive guide to understanding rvalue references, move semantics, universal references, and modern C++ idioms.

    O'Reilly Media · Book · ~$45 · Intermediate

  • Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14

    Use this book to build solid mental models around value categories, move semantics, universal references, and template deduction.

    oreilly.com · O'Reilly Media (Scott Meyers) · Book · ~$49.99 print / ~$42.99 ebook · Intermediate to Advanced

  • LearnCpp.com

    Use this comprehensive, up-to-date guide as your primary tutorial companion from basic syntax and toolchains through standard library algorithms.

    learncpp.com · Alex / LearnCpp · Tutorial series · Free · Beginner to Intermediate

  • LLVM Clang Sanitizers (AddressSanitizer, MemorySanitizer, ThreadSanitizer, UBSan)

    Use these compiler-integrated dynamic analysis tools to detect memory leaks, use-after-free errors, undefined behaviour, and data races.

    clang.llvm.org · LLVM Project · Tool Documentation · Free · Intermediate

  • Official CMake Tutorial & Documentation

    Use this official guide to learn how to structure multi-target C++ projects, manage dependencies, and configure modern standard targets.

    cmake.org · Kitware · Documentation & Tutorial · Free · Beginner to Intermediate

  • r/cpp and r/learncplusplus

    Use these subreddits for community troubleshooting, beginner feedback, and discussions on contemporary C++ articles and ecosystem updates.

    reddit.com · Reddit Community · Forum · Free · All levels

  • Standard C++ Foundation (isocpp.org)

    Use this hub to keep up with ISO standardization news, compiler conformance matrices, and curated conference presentations.

    isocpp.org · Standard C++ Foundation · Community Portal · Free · All levels

  • Tracy Profiler

    Use this high-resolution sampling and frame profiler for deep memory tracking, lock contention profiling, and timeline performance analysis.

    github.com · Bartosz Taudul / wolfpld · Open Source Profiler · Free · Advanced

Forums & Developer Communities

Places to discuss design and code.

  • Include C++ Community

    A welcoming global community and Discord server for discussing modern C++ questions, language features, and code reviews.

    includecpp.org · #include <C++> · Community Discord & Forum · Free · All Levels