Lessons
Move semantics and the rule of five
Lvalue vs rvalue, T&& rvalue references, std::move, the move constructor, move assignment, and the rule of zero.
What to look for:
- std::move does NOT move — it casts to rvalue reference, granting permission to move
- Move constructor: steal the source's resources, leave source in valid-but-empty state
- Mark move constructors noexcept — std::vector uses copy instead of move if not noexcept
- Rule of zero: design classes using STL members (string, vector, unique_ptr) so you need none of the five
std::optional, std::variant, and std::expected
std::optional (nullable value without heap), std::variant (type-safe union), std::visit, std::expected (C++23, result type).
Prerequisite: Practitioner Track
What to look for:
- optional<T> stores T inline — no heap allocation; value_or() for safe extraction
- variant<A, B, C> is a type-safe union — holds exactly one of A, B, or C at a time
- std::visit with a lambda dispatch table: the C++ equivalent of pattern matching
- std::expected<T, E> (C++23): either a value T or an error E — like Rust's Result<T, E>
C++20 concepts and constexpr
Concept syntax, requires clauses, std::integral / std::floating_point / std::totally_ordered, constexpr functions, and consteval.
Prerequisite: Lesson 1
What to look for:
- Concepts give template constraint violations readable error messages — not TMP error walls
- requires expression: requires { expr; } checks that an expression is valid for T
- constexpr function: may run at compile time or runtime depending on inputs
- consteval: must run at compile time — guaranteed constant; compile error if inputs aren't constant
Ranges and views pipeline (C++20)
std::ranges::sort, std::views::filter, std::views::transform, pipe operator |, lazy evaluation, and composing view pipelines.
Prerequisite: Lesson 3
What to look for:
- Views are lazy — they don't compute until iterated; composing views adds no intermediate containers
- Pipe operator: v | views::filter(...) | views::transform(...) — reads left-to-right like a pipeline
- std::ranges::sort(v) is cleaner than std::sort(v.begin(), v.end()) — same algorithm
- views::iota(1, 11) generates {1,2,...,10} lazily — no storage needed
Concurrency: std::thread, mutex, and atomic
std::thread, std::mutex, std::lock_guard, std::atomic, data races, and std::async / std::future.
Prerequisite: Lessons 1–4
What to look for:
- Data race: two threads access the same memory, at least one writes, no synchronisation — undefined behaviour
- std::lock_guard: RAII mutex lock — unlocks automatically when goes out of scope
- std::atomic<int>: thread-safe integer operations without a mutex — use for counters and flags
- std::async: launches a function asynchronously; std::future.get() blocks until result is ready
After this track: You have modern C++ skills. Good next steps: Stroustrup's A Tour of C++ for breadth, Meyers' Effective Modern C++ for depth, and a real project — a command-line tool, a game engine component, or a performance-critical library. The C++ Core Guidelines are essential reading before any production code.
Track quiz
4 questions to check your understanding.
What does std::move actually do to an object?
Why should move constructors be marked noexcept?
What is a C++20 concept?
What is a data race in C++?