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.
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.
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 buildcompiles and outputs your greeting program with zero warnings.How to work through it
- Install GCC/Clang, CMake, and a modern editor with clangd support
- Write a simple CMakeLists.txt targeting C++20 with strict warning flags (-Wall -Wextra -Wpedantic)
- 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
- Create separate header files for each converter category using `#pragma once`
- Implement function logic in matching .cpp files
- Implement an interactive loop in main.cpp reading user selections via std::cin and std::cout
- 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
- Use `<random>` to seed a standard Mersenne Twister engine (`std::mt19937`)
- Write the game loop tracking attempt counts and user guesses
- Check and clear stream error states (`std::cin.clear()` and `std::cin.ignore()`) when parsing fails
- Print formatted post-game statistics upon user quit
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()andalignof()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
- Define structs with identical member types arranged in descending vs mixed size order
- Print `sizeof` and `alignof` along with member offsets using the `offsetof` macro
- 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
- Implement a function that swaps two custom structs via mutable references
- Implement a function that takes a read-only large struct by `const&` and computes an aggregate score
- 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, andstd::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
- Define an `enum class GradeLetter` and a `struct StudentRecord`
- Implement functions to calculate GPA by passing records by const reference
- Provide sorting and lookup functions operating over a collection of records
- Render a clean tabular summary in the console
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
- Declare stack arrays and print element memory addresses to observe memory contiguity
- Re-implement array indexing using pure pointer arithmetic `*(ptr + offset)`
- 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[]anddelete[]. 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
- Create a struct holding data pointer, size, and capacity
- Implement `push_back` with dynamic buffer reallocation and element copying
- Implement cleanup functions that invoke `delete[]`
- 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
- Define a `Node` struct containing data and a `Node* next` pointer
- Implement `push_front`, `push_back`, `erase(value)`, and `reverse` functions
- Implement a recursive or iterative `clear()` function that deletes every node
- Test thoroughly with an empty list, single element list, and multi-element list
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
- Write a class `FileHandle` taking a file path and mode in its constructor
- Call `fclose` inside the destructor `~FileHandle()` if the handle is valid
- Disable copying by deleting copy constructor and copy assignment operator
- 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
Shapewith pure virtual methods forarea(),perimeter(), andrender(). 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
- Define `Shape` with pure virtual functions (`= 0`) and a virtual destructor
- Implement derived classes with `override` keyword on all overridden virtual methods
- Store pointers to shapes in an array and iterate to invoke polymorphic behavior
- 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
- Design an abstract `Entity` base class and derive `Warrior`, `Mage`, and `Rogue`
- Implement a polymorphic `StatusEffect` system (e.g., Poison, Shield) applied each turn
- Maintain strict private data encapsulation, validating mutations via public methods
- Simulate turn order and display dynamic combat logs in the terminal
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
MyStringclass 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:
MyStringpasses unit tests verifying deep copying on lvalue assignment, pointer pilfering onstd::move, self-assignment safety, and zero leaks.How to work through it
- Implement constructor allocating heap buffer and destructor releasing it
- Implement copy constructor and copy assignment using the copy-and-swap idiom
- Implement move constructor and move assignment operator transferring raw pointer ownership and nulling the source
- 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 viastd::cout << vec.How to work through it
- Implement member compound assignment operators (`+=`, `-=`)
- Implement non-member binary arithmetic operators (`+`, `-`) reusing compound assignments
- Implement C++20 three-way comparison operator (`operator<=>`) for default ordering
- 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
Matrixclass combining dynamic memory management, full Rule of Five compliance, bracket indexingoperator()(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
- Store matrix elements in a single contiguous 1D array (`rows * cols`) for cache locality
- Implement constructor, copy/move operations, and destructor satisfying Rule of Five
- Implement `operator()(size_t r, size_t c)` for 2D indexing
- Implement matrix multiplication with boundary dimension checks
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 viastd::shared_ptr, and back-references/cycles usingstd::weak_ptrto 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
- Model nodes and edges using `std::unique_ptr` for exclusive ownership
- Implement shared references with `std::shared_ptr` and `std::make_shared`
- Break potential reference cycles using `std::weak_ptr` and test `.lock()` access
- 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, andstd::unordered_mapacross 1,000 to 500,000 elements.Done when: the benchmark produces an empirical performance report comparing CPU cache locality benefits of
std::vectoragainst node-based containers.How to work through it
- Use `<chrono>` high-resolution clocks to time insertions, lookups, and deletions
- Test contiguous containers (`std::vector`) vs node containers (`std::list`, `std::set`)
- Test sorted associative containers (`std::map`) vs hash tables (`std::unordered_map`)
- 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_mapfor O(1) lookups andstd::listfor 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
- Maintain a `std::list` of key-value pairs representing access recency
- Maintain a `std::unordered_map` mapping keys to list iterators for O(1) access
- Implement `get(key)` moving accessed items to the front of the list
- Implement `put(key, value)` with automatic eviction of the least recently used element when over capacity
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-capacityCircularBuffer<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
- Write a class template parameterized on `typename T` and `size_t Capacity`
- Implement `emplace` using variadic templates and `std::forward`
- Provide copy and move constructors enabled only when `T` supports them
- 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
conceptandrequiresclauses. Define custom concepts likeNumeric,Printable, andSerializable, 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
- Define a custom `concept Numeric = std::integral<T> || std::floating_point<T>`
- Define a concept checking whether a type supports serialization via stream operator `<<`
- Apply `requires` clauses to function templates and evaluate compile-time error clarity
- 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
constexprandconsteval. 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
- Write `constexpr` string view parsing helper functions
- Parse key-value integer configuration pairs into a compile-time lookup table
- Use `static_assert` to validate correct parsing and deliberately trigger build errors on invalid input
- Inspect generated assembly on Compiler Explorer (Godbolt) to verify zero runtime parsing cost
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
forandwhileloops 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
- Replace filtering loops with `std::copy_if` and `std::remove_if`
- Use `std::transform` and `std::reduce` for mapping and aggregation
- Utilize lambda capture lists (`[&]`, `[=]`, `[val = std::move(p)]`) effectively
- 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
forloops and standard algorithms to traverse your tree naturally.Done when: you can execute
for (int val : my_tree)and runstd::finddirectly across your custom tree data structure.How to work through it
- Define nested `iterator` struct with `iterator_category`, `value_type`, `difference_type`, and pointer/reference aliases
- Implement `operator*`, `operator->`, prefix/postfix `operator++`, and `operator==`
- Provide `begin()` and `end()` member functions on the tree class
- 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::rangesand 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
- Read log files as a stream of `std::string_view`
- Construct a processing pipeline using pipe syntax (`| std::views::filter(...) | std::views::transform(...)`)
- Process results lazily without creating intermediary vectors
- Compare pipeline readability and memory usage against traditional loop-based parsing
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 withstd::mutexandstd::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
- Spawn worker threads that loop waiting on a shared work queue
- Protect the task queue with `std::mutex` and `std::unique_lock`
- Signal waiting threads when work arrives via `std::condition_variable::notify_one`
- 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, andstd::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
- Partition input chunks across available hardware concurrency (`std::thread::hardware_concurrency`)
- Dispatch worker tasks via `std::async(std::launch::async, ...)`
- Collect and combine results using `future.get()`
- 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
- Create a ring buffer with atomic head and tail indices
- Use `std::memory_order_release` when publishing written items
- Use `std::memory_order_acquire` when reading published items
- Verify thread safety and benchmark latency against a mutex-based queue
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/deletecalls.How to work through it
- Pre-allocate a contiguous memory arena of `N * BlockSize` bytes
- Maintain an in-place linked list of free blocks within the unused arena memory
- Implement `allocate()` popping from the free list and `deallocate()` returning blocks to the list
- 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
perfor 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
- Profile the unoptimized code using `perf record` and `perf report`
- Identify cache misses and branch mispredictions
- Refactor loops for cache line locality (tiling/blocking) and enable compiler auto-vectorization flags (`-O3 -march=native`)
- 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
- Implement RAII wrappers for network sockets and file descriptors
- Integrate your ThreadPool to handle client connections concurrently
- Use your LRU cache and custom memory allocator for fast in-memory key storage
- Write a robust command parser using C++20 ranges and string_views
- 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.
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