🌍 C++ Programming · subject
C++ Programming Advanced Topics Syllabus
The Advanced Topics syllabus for C++ Programming in full: 5 chapters and 17 topics, every one listed below, plus 62 Advanced Topics flashcards with answers.
Advanced Topics syllabus: all 5 chapters
Expand any chapter to see its topics and sub-topics.
-
Templates
3 topics- Function Templates
- Class Templates
- Template Specialization
-
Exception Handling
3 topics- Try, Catch, and Throw
- Standard Exceptions
- User-defined Exceptions
-
Standard Template Library (STL)
4 topics- Containers
- Iterators
- Algorithms
- Function Objects
-
File Handling
4 topics- File Streams
- Reading from Files
- Writing to Files
- Binary Files
-
Multithreading
3 topics- Thread Management
- Mutex and Lock
- Thread Communication
C++ Programming Advanced Topics flashcards — 62 questions with answers
What is a function template in C++, and what keyword introduces it?
A function template is a blueprint for generating a family of functions that operate on different data types without rewriting code. It is introduced with the `template` keyword followed by a parameter list, e.g. `template <typename T> T max(T a, T b);`.
What is the difference between the keywords `typename` and `class` in a template parameter list?
In a template parameter declaration (e.g. `template <typename T>` vs `template <class T>`) they are completely interchangeable and mean the same thing. `typename` is also required elsewhere to disambiguate a dependent type name inside a template.
What is template argument deduction for function templates?
It is the process by which the compiler automatically infers the template type parameters from the types of the function-call arguments, so you can write `max(3, 7)` instead of explicitly `max<int>(3, 7)`.
When must you explicitly specify template arguments for a function template instead of relying on deduction?
When the type cannot be deduced from the arguments (e.g. the type appears only in the return type or as a non-deduced context), when you need a different type than deduced, or for explicit conversion, e.g. `func<double>(2)`.
What is a non-type template parameter? Give an example.
A non-type template parameter is a compile-time constant value (not a type) passed to a template, such as an integer, pointer, or reference. Example: `template <typename T, int N> class Array { T data[N]; };` where `N` is a non-type parameter.
What is a class template in C++?
A class template is a blueprint for generating a family of classes parameterized on one or more types or values, allowing generic data structures. Example: `template <typename T> class Stack { ... };`, instantiated as `Stack<int>`.
When are class templates instantiated, and why must their definitions usually be in header files?
They are instantiated at compile time when used with concrete arguments (e.g. `Stack<int>`). Because the compiler must see the full definition to generate code for each instantiation, template definitions are typically placed entirely in header files rather than split into a .cpp file.
How do you define a member function of a class template outside the class body?
You prefix it with the template parameter list and qualify it with the templated class name, e.g. `template <typename T> void Stack<T>::push(const T& x) { ... }`.
What is template specialization? Distinguish full (explicit) from partial specialization.
Template specialization provides a custom implementation for specific template arguments. Full (explicit) specialization fixes all parameters (e.g. `template <> class Foo<char>`). Partial specialization fixes some parameters or narrows their form (e.g. `template <typename T> class Foo<T*>`); it is allowed for class templates but not function templates.
What is the syntax for a full explicit specialization of a class template `template <typename T> class Foo`?
`template <> class Foo<int> { ... };` — an empty `template <>` parameter list followed by the class name with the concrete argument.
Why can't function templates be partially specialized, and what is the recommended alternative?
The C++ standard forbids partial specialization of function templates. The recommended alternative is function overloading (adding overloaded function templates) or delegating to a partially specialized class/struct template.
What are the three keywords that make up C++ exception handling, and what does each do?
`try` encloses code that may throw; `throw` raises an exception object; `catch` defines a handler that matches and handles a thrown exception of a given type.
Describe the flow of control when an exception is thrown inside a `try` block.
Execution of the try block stops immediately, the stack unwinds (destroying local objects), and control transfers to the first matching `catch` handler by type. If none matches in the current scope, unwinding propagates up the call stack until a handler is found or `std::terminate` is called.
What is stack unwinding in the context of C++ exceptions?
Stack unwinding is the process, during exception propagation, of destroying automatic (local) objects in reverse order of construction as each function's stack frame is exited, ensuring their destructors run and resources are released.
How do you write a catch-all handler that catches any exception type?
`catch (...) { ... }` — the ellipsis matches exceptions of every type, but gives no access to the exception object itself.
Why should exceptions generally be caught by reference (e.g. `catch (const std::exception& e)`)?
Catching by reference avoids object slicing (which would lose the derived type's data/behavior when caught by value) and avoids an unnecessary copy, while still preserving polymorphic behavior via `what()`.
What is the base class of the standard exception hierarchy, and what member function does it provide?
`std::exception` (in `<exception>`) is the base class. It provides the virtual member function `what()`, which returns a `const char*` describing the error.
Name and distinguish two standard exceptions derived from `std::logic_error` and two derived from `std::runtime_error`.
From `std::logic_error` (errors detectable before run, in program logic): `std::invalid_argument`, `std::out_of_range`, `std::length_error`, `std::domain_error`. From `std::runtime_error` (errors detectable only at run time): `std::range_error`, `std::overflow_error`, `std::underflow_error`.
Which standard exception does `std::vector::at()` throw on an invalid index, and which base class is it derived from?
It throws `std::out_of_range`, which derives from `std::logic_error`, which in turn derives from `std::exception`.
Which exception is thrown when `new` fails to allocate memory?
`std::bad_alloc` (defined in `<new>`), which derives from `std::exception`.
Show the other 42 Advanced Topics flashcards
How do you create a user-defined exception class properly in C++?
Derive it publicly from `std::exception` (or a subclass like `std::runtime_error`), and override `what()` as `const char* what() const noexcept override`. Deriving from `std::runtime_error` lets you pass a message string to its constructor and inherit `what()`.
Why should a custom exception's `what()` override be marked `noexcept`?
Because `std::exception::what()` is declared `noexcept`; an override must not throw. Marking it `noexcept` matches the base signature and guarantees the error-reporting path itself cannot throw during exception handling.
What is a container in the C++ Standard Library, and what are the three broad categories?
A container is a class template that stores and manages a collection of objects. The three categories are: sequence containers (`vector`, `deque`, `list`, `array`, `forward_list`), associative containers (`set`, `map`, `multiset`, `multimap`), and unordered associative containers (`unordered_set`, `unordered_map`, etc.). Container adaptors (`stack`, `queue`, `priority_queue`) are a fourth group.
Compare `std::vector` and `std::list` in terms of storage and complexity.
`std::vector` stores elements contiguously, giving $O(1)$ random access and amortized $O(1)$ push_back, but $O(n)$ insertion/deletion in the middle. `std::list` is a doubly linked list with $O(1)$ insertion/deletion anywhere (given an iterator) but no random access and $O(n)$ traversal to a position.
What is the difference between `std::map` and `std::unordered_map` regarding ordering and lookup complexity?
`std::map` is ordered (typically a balanced red-black tree) with keys sorted, giving $O(\log n)$ lookup/insertion. `std::unordered_map` is a hash table with no ordering, giving average $O(1)$ but worst-case $O(n)$ lookup/insertion.
What distinguishes `std::set`/`std::map` from `std::multiset`/`std::multimap`?
`set` and `map` require unique keys (duplicate keys are rejected), whereas `multiset` and `multimap` allow multiple elements with equivalent keys.
What is an iterator in C++, and what are the two most fundamental operations it supports?
An iterator is an object that abstracts a position in a container and generalizes a pointer. The two fundamental operations are dereferencing (`*it`) to access the element and increment (`++it`) to advance to the next element.
List the five iterator categories from least to most capable.
Input iterator, Output iterator, Forward iterator, Bidirectional iterator, Random-access iterator. (C++20 adds Contiguous iterator as the most capable.) Each category supports the operations of the weaker ones plus additional capabilities.
Which iterator category does `std::list` provide, and which does `std::vector` provide?
`std::list` provides bidirectional iterators (supporting `++` and `--` but not `+n`). `std::vector` provides random-access iterators (supporting arithmetic like `it + n`, `it - it`, and comparison).
What is the difference between `begin()`/`end()` and the half-open range they define?
`begin()` returns an iterator to the first element and `end()` returns an iterator one past the last element. Together they define the half-open range `[begin, end)`; iterating stops when the iterator equals `end()`, which is never dereferenced.
What is a common cause of iterator invalidation in a `std::vector`?
Operations that reallocate the internal buffer (e.g. `push_back` when capacity is exceeded, `insert`, `resize`) invalidate all existing iterators, pointers, and references. Erasing elements invalidates iterators at and after the erase point.
What is the STL `<algorithm>` header, and how do algorithms interact with containers?
`<algorithm>` provides a set of generic function templates (e.g. `sort`, `find`, `copy`, `accumulate`) that operate on ranges via iterators rather than on containers directly. This iterator-based decoupling lets one algorithm work with any container that provides suitable iterators.
What does `std::sort` require of its iterators, and what is its typical time complexity?
`std::sort` requires random-access iterators (so it works on `vector`/`deque`/array but not `list`, which has `list::sort`). Its average complexity is $O(n \log n)$ comparisons.
Contrast `std::find` and `std::binary_search`.
`std::find` performs a linear search over any input range and returns an iterator to the first match, complexity $O(n)$. `std::binary_search` requires the range to be already sorted, runs in $O(\log n)$, and returns only a `bool` indicating presence.
What does `std::for_each` do, and how does it relate to a range-based for loop?
`std::for_each(first, last, fn)` applies the callable `fn` to each element in the range `[first, last)`. It predates and is functionally similar to a range-based `for` loop, though the range-based `for` (C++11) is now usually preferred for readability.
What is a function object (functor) in C++?
A function object is an instance of a class that overloads `operator()`, allowing the object to be called like a function (e.g. `obj(x)`). Unlike a plain function, a functor can carry state in its member variables.
What advantage does a function object have over a plain function pointer when passed to an STL algorithm?
A functor can hold state (member data) between calls, can be inlined by the compiler for better performance, and its type is known at compile time enabling optimization, whereas a function pointer is opaque and calls are typically not inlined.
How does a C++ lambda expression relate to function objects?
A lambda expression is syntactic sugar that the compiler translates into an unnamed function-object (closure) class with an overloaded `operator()`. Captured variables become member data of that generated closure type.
Name two standard predefined function objects from `<functional>` and their use.
Examples: `std::less<T>` (returns `a < b`, the default comparator for sorted containers and `sort`), `std::greater<T>` (returns `a > b`, for descending order), `std::plus<T>`, `std::multiplies<T>` used with `accumulate`/`transform`.
What are the three main file stream classes in C++ and the header they come from?
From `<fstream>`: `std::ifstream` (input/read from file), `std::ofstream` (output/write to file), and `std::fstream` (both input and output).
List the common file open modes (`std::ios` flags) and what each does.
`ios::in` (read), `ios::out` (write), `ios::app` (append to end), `ios::ate` (seek to end on open), `ios::trunc` (truncate/discard existing contents), `ios::binary` (binary mode). Flags can be combined with the bitwise OR operator `|`.
How do you check whether a file was opened successfully in C++?
Test the stream in a boolean context or call `is_open()`: e.g. `std::ifstream f("data.txt"); if (!f) { /* failed */ }` or `if (!f.is_open()) { ... }`.
What is RAII with respect to file streams, and when is a file closed automatically?
File stream objects follow RAII: the file is opened in the constructor and closed automatically in the destructor when the stream object goes out of scope, so an explicit `close()` is often unnecessary (though useful to release the resource early).
Give two common ways to read text from a file line by line versus token by token.
Line by line: `std::getline(inFile, line)` reads a whole line into a `std::string`. Token by token: the extraction operator `inFile >> token` reads whitespace-delimited tokens. Both are typically used in a `while` loop that continues while the stream stays in a good state.
How do you detect end-of-file correctly when reading in a loop?
Test the read operation itself in the loop condition, e.g. `while (inFile >> x)` or `while (std::getline(inFile, line))`. Do NOT loop on `while (!inFile.eof())`, because `eof()` is only set after a failed read, causing the last item to be processed twice.
How do you write formatted text to a file, and how do you flush it?
Use the insertion operator: `outFile << value << '\n';`. Output is flushed automatically on close/destruction, or manually with `outFile.flush()` or by inserting `std::endl` (which writes a newline AND flushes).
What is the difference between text mode and binary mode file I/O?
Text mode may translate characters (e.g. newline conversions on Windows) and is meant for human-readable data. Binary mode (`ios::binary`) writes/reads raw bytes with no translation, preserving the exact byte representation—required for non-text data and reliable fixed-size records.
Which member functions read and write raw binary data, and what are their parameter types?
`ostream::write(const char* buffer, std::streamsize count)` writes raw bytes, and `istream::read(char* buffer, std::streamsize count)` reads raw bytes. The object pointer is typically cast with `reinterpret_cast<char*>(&obj)` and `count` is `sizeof(obj)`.
What functions reposition the read/write position in a file, and what does the tell-family return?
`seekg(pos)`/`seekp(pos)` set the get (read) and put (write) positions; `tellg()`/`tellp()` return the current get/put positions. `seekg` also accepts an offset and a base such as `ios::beg`, `ios::cur`, or `ios::end`.
What header and class launch a new thread in C++11, and how is the thread function supplied?
The `<thread>` header provides `std::thread`. A thread is launched by constructing a `std::thread` object with a callable (function, lambda, or functor) and its arguments, e.g. `std::thread t(func, arg1);`, which begins execution immediately.
What is the difference between `join()` and `detach()` on a `std::thread`?
`join()` blocks the calling thread until the target thread finishes, then releases its resources. `detach()` separates the thread to run independently in the background. Exactly one of the two must be called before the `std::thread` is destroyed, or `std::terminate` is invoked.
What is a data race, and what is the general rule for avoiding one?
A data race occurs when two or more threads access the same memory location concurrently, at least one access is a write, and there is no synchronization; the result is undefined behavior. The rule: protect shared mutable data with synchronization (mutexes, atomics) so accesses do not overlap.
What is a `std::mutex` and what are its two core operations?
A `std::mutex` (from `<mutex>`) is a mutual-exclusion primitive that lets only one thread hold it at a time, protecting a critical section. Its core operations are `lock()` (acquire, blocking until available) and `unlock()` (release).
Why prefer `std::lock_guard` or `std::unique_lock` over calling `mutex.lock()`/`unlock()` directly?
They are RAII wrappers that lock the mutex on construction and automatically unlock on destruction (including during exception unwinding), preventing forgotten unlocks and deadlocks from early returns or thrown exceptions.
How does `std::unique_lock` differ from `std::lock_guard`?
`std::lock_guard` is minimal: it locks on construction and unlocks on destruction with no other operations. `std::unique_lock` is more flexible—it supports deferred locking, manual `lock()`/`unlock()`, timed locking, ownership transfer (movable), and is required for use with condition variables.
What is a deadlock, and name one strategy to prevent it when locking multiple mutexes.
A deadlock is a state where two or more threads each wait forever for a lock held by another. Prevention strategies include always acquiring multiple locks in a consistent global order, or using `std::lock(m1, m2)` / `std::scoped_lock(m1, m2)` which lock several mutexes atomically without deadlock.
What synchronization primitive is used for thread communication where one thread waits for a condition set by another?
`std::condition_variable` (from `<condition_variable>`). One thread waits on it (releasing an associated `std::unique_lock`), and another thread signals with `notify_one()` or `notify_all()` when the condition changes.
Why must `condition_variable::wait` be used with a predicate (or in a loop), and how is the predicate form written?
To guard against spurious wakeups and lost/early notifications, `wait` should re-check a condition. The predicate form `cv.wait(lock, []{ return ready; });` atomically releases the lock, sleeps, and only returns when both notified and the predicate is true—equivalent to a `while (!pred()) cv.wait(lock);` loop.
What is the difference between `notify_one()` and `notify_all()` on a condition variable?
`notify_one()` wakes a single thread waiting on the condition variable (if any). `notify_all()` wakes all waiting threads, which then re-contend for the lock and re-check their predicates; use it when a state change could satisfy multiple waiters (e.g. a broadcast).
How does `std::future` and `std::promise` enable thread communication for returning a value?
A `std::promise<T>` is set by the producing thread via `set_value()` (or `set_exception()`), and the consuming thread retrieves the result through the associated `std::future<T>` using `get()`, which blocks until the value is ready. This provides a one-time, thread-safe channel for a result or exception.
What does `std::atomic<T>` provide, and how does it differ from using a mutex?
`std::atomic<T>` (from `<atomic>`) makes individual read-modify-write operations on a variable indivisible and race-free without an explicit lock, typically using hardware atomic instructions. It is lighter-weight than a mutex for simple shared variables (e.g. counters/flags) but does not protect multi-variable invariants, which still require a mutex.
What is the purpose of `std::this_thread::sleep_for` and `std::this_thread::get_id`?
`std::this_thread::sleep_for(duration)` blocks the current thread for at least the given time span (e.g. `std::chrono::milliseconds(100)`). `std::this_thread::get_id()` returns the unique `std::thread::id` of the currently executing thread, useful for logging and identification.
C++ Programming Advanced Topics FAQ
What is in the C++ Programming Advanced Topics syllabus?
C++ Programming Advanced Topics is split into 5 chapters: Templates, Exception Handling, Standard Template Library (STL), File Handling and Multithreading. Together they contain 17 topics.
How many chapters are in C++ Programming Advanced Topics?
5 chapters, containing 17 topics. The largest chapter is Standard Template Library (STL), with 4 topics.
Are there flashcards for C++ Programming Advanced Topics?
Yes — a 62-card Advanced Topics deck, printed in full in the flashcards section of this page and available in the Examius app with spaced repetition. The free plan covers one exam of your choice, including its flashcards; Examius Pro, a one-time purchase, unlocks every other exam and deck.