C++ Interview Questions & Answers (2026)
These interviews test fundamental syntax, memory management, STL mastery, and modern C++ idioms. A candidate passes by explaining core concepts clearly, demonstrating code‑level reasoning, and showing awareness of trade‑offs such as safety versus performance. Highlighting practical examples, edge‑case handling, and recent language features signals depth and readiness for production‑grade C++ work.
20 questions · updated Aug 29, 2026
Quick facts
| Typical rounds | Phone screen, coding challenge, system design, on‑site technical deep‑dive |
| Core focus | Memory safety, STL usage, concurrency, C++20/23 features |
| Preferred background | 2‑5 years of C++ development, familiarity with build systems |
| Success metric | Clarity of explanation, correctness of code, and discussion of complexity |
Questions
Beginner
Explain the Rule of Three, Rule of Five, and Rule of Zero in C++.
The Rule of Three states that if a class defines a destructor, copy constructor, or copy‑assignment operator, it should define all three to manage resources correctly. The Rule of Five extends this to include move constructor and move‑assignment operator introduced in C++11, because move semantics affect resource ownership. The Rule of Zero advises designing classes that rely on RAII members so they need no custom special member functions, reducing bugs and simplifying maintenance.
What is a dangling pointer and how can you avoid it?
A dangling pointer points to memory that has been freed or gone out of scope. Accessing it leads to undefined behavior. To avoid it, always set pointers to nullptr after delete, use smart pointers (unique_ptr or shared_ptr) that automatically nullify on destruction, and prefer objects with automatic storage duration when possible. Static analysis tools can also detect potential dangling references.
How does std::move differ from a copy operation?
std::move casts its argument to an rvalue reference, signaling that the object's resources can be transferred rather than duplicated. A copy operation creates a new object with its own copy of the data, invoking the copy constructor. Move semantics invoke the move constructor, which typically steals internal pointers, leaving the source in a valid but unspecified state, improving performance for large objects.
Describe the differences between std::vector and std::list.
std::vector stores elements contiguously, offering O(1) random access and cache‑friendly iteration, but insertions or deletions in the middle require shifting elements (O(n)). std::list is a doubly‑linked list providing O(1) insertion and removal at any position, but no random access and higher memory overhead per element. Choose vector for performance‑critical iteration, list only when frequent middle modifications outweigh cache costs.
What is undefined behavior and give an example in C++?
Undefined behavior (UB) occurs when the C++ standard imposes no requirements on the result of a program construct, allowing any outcome including crashes. A classic example is signed integer overflow: int x = INT_MAX; x += 1; The result is UB, so the compiler may optimize assuming overflow never happens, leading to surprising bugs. Safe code avoids UB by using well‑defined operations.
Explain how RAII works and why it is important.
RAII (Resource Acquisition Is Initialization) ties resource lifetimes to object lifetimes. A constructor acquires a resource (e.g., memory, file handle) and the destructor releases it. This guarantees deterministic cleanup even when exceptions occur, preventing leaks. In C++, smart pointers, std::lock_guard, and std::unique_lock are RAII wrappers that simplify safe resource management and reduce manual error‑prone code.
Intermediate
What are constexpr functions and when should you use them?
constexpr functions are evaluated at compile time when given constant arguments, enabling their results to be used in contexts requiring constant expressions, such as array sizes or template parameters. Use them for pure computations without side effects, like mathematical utilities or compile‑time lookup tables. If a constexpr function cannot be evaluated at compile time, it falls back to a regular runtime call, so design them to be simple and deterministic.
How does std::unique_ptr differ from std::shared_ptr?
std::unique_ptr owns a resource exclusively; it cannot be copied, only moved, which enforces single ownership and incurs no reference‑count overhead. std::shared_ptr allows multiple owners via a reference count; copying increments the count, and the resource is freed when the count reaches zero. Use unique_ptr for clear ownership semantics and performance, and shared_ptr when shared ownership is required, but be mindful of cyclic references.
Explain the concept of move semantics and its impact on performance.
Move semantics enable the transfer of resources from a temporary or expiring object to a new one without deep copying. By implementing move constructors and move‑assignment operators, containers like std::vector can relocate elements efficiently during reallocation, reducing allocations and copies. This yields significant performance gains for large objects or containers, especially in high‑throughput code, while preserving correctness by leaving the source in a valid but empty state.
What is the difference between std::map and std::unordered_map?
std::map is an ordered associative container implemented as a balanced binary tree, providing O(log n) lookup, insertion, and deletion, and preserving key order. std::unordered_map is a hash table offering average O(1) operations but no ordering guarantee. Choose std::map when ordered traversal or range queries are needed; choose unordered_map for fastest key‑based access when order is irrelevant.
How do you prevent data races when using std::thread?
Data races occur when multiple threads access the same memory without proper synchronization. Prevent them by protecting shared data with mutexes (std::mutex, std::recursive_mutex) and using lock guards (std::lock_guard) to ensure exception‑safe locking. For read‑heavy workloads, consider shared_mutex for reader‑writer locks. Atomic types (std::atomic) provide lock‑free synchronization for simple variables, and higher‑level constructs like futures or thread‑safe queues can encapsulate safe communication patterns.
What are lambda captures and how do they affect object lifetimes?
Lambda captures specify which surrounding variables a lambda can access. By value ([=]) the lambda copies the variable, extending its lifetime to the lambda's own. By reference ([&]) it holds a reference, so the captured object must outlive the lambda; otherwise, using it leads to undefined behavior. C++14 introduced init‑capture ([x = std::move(y)]) to move resources into the lambda, enabling safe ownership transfer for asynchronous tasks.
Explain the purpose of std::enable_if and give a simple use case.
std::enable_if is a SFINAE (Substitution Failure Is Not An Error) utility that conditionally removes a function or overload from the candidate set based on a compile‑time boolean expression. A common use case is to enable a template only for integral types: template <typename T> std::enable_if_t<std::is_integral_v<T>, void> foo(T t) { /* ... */ }. This prevents accidental instantiation with unsupported types and provides clearer compile‑time diagnostics.
Advanced
What are concepts in C++20 and why are they useful?
Concepts are compile‑time predicates that constrain template parameters, improving readability and error messages. They allow developers to express requirements like 'T must be iterable' or 'T must support addition' using the requires clause or concept definitions. By enforcing these constraints early, concepts catch misuse before instantiation, reduce template metaprogramming boilerplate, and make generic code self‑documenting, leading to more maintainable libraries.
Describe how the copy‑elision and mandatory NRVO rules work in C++17 and later.
Copy‑elision permits the compiler to omit temporary object copies, constructing the object directly into its final storage. Since C++17, certain elisions are mandatory: when returning a local object by value, the compiler must perform NRVO (named return value optimization) or treat the return as a direct construction. This eliminates unnecessary copy/move constructors, improving performance and simplifying reasoning about object lifetimes, as developers can rely on zero‑overhead returns.
How does the memory model in C++17 define happens‑before relationships?
The C++ memory model defines a happens‑before relation to order operations across threads. An atomic store with release semantics happens‑before an atomic load with acquire semantics on the same variable. Additionally, sequenced‑before within a single thread contributes to happens‑before across threads via synchronization operations. Understanding these relationships lets a candidate reason about visibility, ordering, and avoid data races when designing lock‑free algorithms.
Explain the difference between std::shared_mutex and std::mutex.
std::mutex provides exclusive locking: only one thread can hold it at a time. std::shared_mutex supports multiple concurrent readers (shared locks) while still allowing exclusive writers. Readers acquire a shared_lock, which does not block other readers, but any writer must acquire an exclusive lock, blocking both readers and other writers. Use shared_mutex when read‑heavy workloads benefit from parallel reads, and mutex when contention is low or writes dominate.
What is the purpose of the three-way comparison operator (<=>) introduced in C++20?
The three-way comparison operator, or spaceship operator, provides a single function that returns a std::strong_ordering, std::weak_ordering, or std::partial_ordering, encapsulating all relational comparisons. Implementing operator<=> automatically generates operator==, operator<, operator<=, etc., reducing boilerplate. It also enables defaulted comparisons (e.g., struct S { int a; std::string b; auto operator<=> = default; };) for concise, consistent ordering semantics across user‑defined types.
How do coroutines work in C++20 and what problems do they solve?
Coroutines are functions that can suspend execution and resume later, expressed with co_await, co_yield, and co_return. The compiler transforms a coroutine into a state machine with a promise type handling the lifecycle. They simplify asynchronous code by allowing sequential style without callbacks, improve readability, and enable lazy generators. By decoupling suspension points from thread management, coroutines help write efficient, non‑blocking I/O and complex control flows.
What are the trade‑offs between using raw pointers and smart pointers in performance‑critical code?
Raw pointers have zero overhead and can be optimal for tight loops or low‑level systems where allocation patterns are controlled. However, they require manual lifetime management, increasing risk of leaks and dangling references. Smart pointers add deterministic destruction (unique_ptr) or shared ownership (shared_ptr) with minimal runtime cost, but shared_ptr incurs atomic reference‑count updates, which can degrade performance in high‑contention scenarios. Choose raw pointers when ownership is clear and lifetimes are managed externally; otherwise, prefer smart pointers for safety.
Common mistakes
- Confusing copy semantics with move semantics, leading to unnecessary copies.
- Using raw pointers for ownership instead of smart pointers, causing memory leaks.
- Neglecting to consider undefined behavior such as signed overflow or iterator invalidation.
- Overlooking thread‑safety, e.g., accessing shared data without proper synchronization.
- Relying on compiler‑specific extensions instead of standard C++ features.
Study plan
- Review core language rules: lifetime, ownership, and the Rule of Five.
- Master STL containers, iterators, and algorithm complexities.
- Practice modern features: constexpr, concepts, and coroutines with small projects.
- Solve concurrency problems using std::thread, mutexes, and atomics.
- Run timed coding interviews on platforms focusing on C++ performance and edge cases.
- Mock interview with a peer, focusing on explaining reasoning and trade‑offs.
FAQ
How much C++ syntax should I memorize for an interview?
Focus on commonly used constructs: smart pointers, move semantics, lambda syntax, and STL usage. Deep memorization of rarely used features isn’t needed; understanding concepts and being able to apply them is more valuable.
Do interviewers expect me to write production‑ready code?
They expect clean, correct code that demonstrates good practices. Include error handling, RAII, and clear naming, but you don’t need full logging or configuration layers. Emphasize readability and correctness.
What is the best way to demonstrate knowledge of C++20 features?
Integrate features like concepts, ranges, and the spaceship operator into solutions. Explain why they simplify code or improve safety, and discuss any compiler support considerations.
How important is performance optimization in C++ interviews?
Very important for system‑level roles. Show awareness of algorithmic complexity, avoid unnecessary copies, and discuss trade‑offs such as using move semantics or selecting appropriate containers.
Should I bring up design patterns during a C++ interview?
Mention patterns only when they naturally fit the problem, such as RAII for resource management or the Strategy pattern for interchangeable algorithms. Overusing them can appear forced.
Related
Ready for your next interview?
Download MiPrep AI. Load your resume and the job description. Show up ready.
Free tier · No credit card · macOS 14+ · Windows 10+
Free tier · No credit card · Runs on your Mac or Windows machine