Перейти к содержанию

💡 TL;DR:The most frequently asked C++ interview questions with concise answers and deep dives: const, static, virtual functions, smart pointers, STL internals, move semantics, multithreading and more.

Last updated:2026-11-10

C++ Interview Questions and Answers

A curated list of the most frequently asked C++ interview questions, each with a concise answer you can give in an interview and a link to a deep-dive article with code, internals, and pitfalls. It covers language fundamentals, OOP, memory management, STL internals, modern C++ (11/17/20), templates, and concurrency — and ends with the C-language questions C++ candidates are still expected to answer.

Use it as a checklist before an interview, or as a study map: every answer links to the full treatment in the C++那些事 (Stories About C++) guide.

1. Language Fundamentals

What does const mean in C++? What are const pointers vs pointers to const?

const promises immutability at compile time. const int* p (pointer to const) forbids writing through p but lets p re-point; int* const p (const pointer) forbids re-pointing but allows writing; const int* const p forbids both. Also distinguish compile-time constants from const in declarations (which have external linkage in C++ and internal in C), and where constexpr is the better tool.

→ Deep dive: C++ const Constants & Qualifiers and The const Family in C++

What is static in C++? List all its uses.

Four distinct meanings: (1) file-scope internal linkage for globals/functions; (2) function-local variables with a single shared instance initialized once; (3) per-class member variables shared by all instances; (4) per-class member functions callable without an object. Interviewers usually follow up with initialization order and thread-safety of function-local statics (guaranteed since C++11).

→ Deep dive: C++ static Members & Lifetime

struct vs class in C++?

Only two differences: default access (public for struct, private for class) and default inheritance mode. Everything else — constructors, virtual functions, templates — is identical for both. Choosing between them is convention, not mechanics.

→ Deep dive: struct vs class

What is the difference between pointers and references?

A reference must be bound at initialization and can never be null or reseated; a pointer can be null, reassigned, and arithmetic applies. References enable operator overloading with value-like syntax. Prefer references for "always bound" parameters, pointers when "no object" is a valid state.

→ Deep dive: C++ Pointers & References

When does the compiler actually inline a function?

inline is a hint, not a command: the compiler decides by cost model, and it mainly solves the One-Definition-Rule for multi-TU definitions. Member functions defined in-class are implicitly inline. Inlining can also happen without the keyword (link-time optimization).

→ Deep dive: C++ inline Functions

What does sizeof return for common types, and what does it not measure?

sizeof yields the byte size of the type representation, including padding — it does not measure heap allocations behind a pointer (sizeof(std::string) is the size of the string object, not the characters). Watch alignment rules and why sizeof on a struct with bit fields surprises people.

→ Deep dive: The C++ sizeof Operator and C++ Bit Fields

Why does volatile NOT make code thread-safe?

volatile only forbids the compiler from caching/eliminating accesses — it inserts no memory barriers and creates no atomicity or happens-before relationships. For inter-thread communication use std::atomic and mutexes; volatile is for memory-mapped I/O.

→ Deep dive: The C++ volatile Keyword

What is the explicit keyword for?

It stops single-argument constructors (and conversion operators, since C++11) from creating implicit conversions. Classic example: preventing MyVec v = 10; from compiling. Essential on any single-arg constructor whose argument is not semantically the value of the type.

→ Deep dive: The C++ explicit Keyword

union, macro pitfalls, and extern linkage — still asked?

Yes, especially in systems roles: unions for type-punning-free memory reuse (now std::variant in modern code), macros' lack of scope/type-checking (prefer constexpr/inline functions), and extern "C" disabling name mangling for C interop.

→ Deep dive: C++ union · C++ Macros & Conditional Compilation · C++ extern & Linkage

2. OOP and Polymorphism

How do virtual functions work? What are vptr and vtable?

Each polymorphic class gets a compiler-generated vtable of function pointers; each object carries a hidden vptr to its dynamic type's vtable. A virtual call loads the vptr, indexes the slot, and indirectly calls — that is the runtime cost (one indirection, not "slow"). Constructors can't be virtual; destructors of base classes must be.

→ Deep dive: C++ virtual Functions and C++ vptr & vtable

Pure virtual functions and abstract classes — what can't they do?

A pure virtual (= 0) marks a function with no default implementation; the class becomes abstract and can't be instantiated. Pure-virtual-with-body exists (subclasses may call it explicitly). Abstract classes define interfaces; the destructor question (protected non-virtual vs public virtual) is a common follow-up.

→ Deep dive: Pure Virtual Functions & Abstract Classes

Can you implement polymorphism in C?

Yes — hand-rolled vtables: a struct of function pointers embedded as the first member, with subclasses sharing the prefix layout. Understanding this demystifies what C++ generates for you.

→ Deep dive: C-Style Polymorphism in C++

What is this and when is it typed differently?

this is a pointer to the current object; in a const member function it becomes const T*. In constructors/destructors its dynamic type is the class under construction — which is why virtual calls don't dispatch to derived overrides there.

→ Deep dive: The C++ this Pointer

3. Memory Management

new/delete vs malloc/free?

new calls constructors, returns a typed pointer, and throws on failure (new(std::nothrow) returns null); malloc only allocates raw bytes. Mismatching them (free on new'd memory) is UB. Placement new, operator new overloading, and alignment (C++17 std::aligned_alloc / alignas) are frequent follow-ups.

→ Deep dive: C++ Memory & Debugging series

How do you pass smart pointers as parameters?

By value only when transferring/borrowing ownership semantics demand it; pass unique_ptr<T>&& to take ownership, raw pointer or reference just to use the object. Taking shared_ptr by value copies a control block for no reason. This is the single most practical smart-pointer interview question.

→ Deep dive: Smart Pointers as Parameters

How would you hunt down a memory leak in production?

Reproduce under a tool: Valgrind memcheck for small cases, Massif/heaptrack for growth analysis, ASan (-fsanitize=address) for CI, and __gnu_cxx::freeres/custom new-hooks for targeted builds. Match every allocation with a deallocation strategy: RAII first.

→ Deep dive: Hunting Memory Leaks in Practice

What is EBO and why do empty classes still take 1 byte?

Distinct objects need distinct addresses, so sizeof(empty) is at least 1 — which pads base-class subobjects and members. Empty Base Optimization makes an empty base occupy zero space; C++20 [[no_unique_address]] does the same for members. This is how std::tuple avoids bloating.

→ Deep dive: STL EBO: Empty Base Optimization

4. STL Internals

How does std::vector grow, and when do iterators invalidate?

Geometric growth (×1.5–2): when capacity is exceeded, a new buffer is allocated, elements are moved/copied, and the old is freed — invalidating all iterators/pointers. push_back amortizes O(1). reserve avoids repeated reallocation; resize changes size, reserve only capacity.

→ Deep dive: STL Source-Code Analysis: vector and vector resize vs reverse

map vs unordered_map — implementation and choice?

map is a red-black tree: ordered iteration, O(log n) operations, iterator stability. unordered_map is a bucket-array hash table: O(1) average, rehashing invalidates iterators but not pointers, and requires a hash + equality. Choose by whether you need ordering; know both worst cases.

→ Deep dive: STL Red-Black Tree · STL map & multimap · STL Source-Code Analysis: unordered_map

How is a hashtable implemented in the libstdc++ STL?

Prime-count bucket array with chaining; single-element buckets store nodes, and since C++11 unordered_map keeps a singly-linked list of all elements. Know rehash policy (load_factor, max_load_factor) and why your custom key type needs std::hash specialization.

→ Deep dive: STL hashtable and Hand-Writing a Hash Table

What are traits? Why does the STL need them?

Traits are compile-time metadata about types (iterator_traits<T>::value_type) so generic code can adapt: the same std::copy dispatches on random-access vs forward iterators for memmove fast paths. This is the gateway question to template metaprogramming.

→ Deep dive: STL traits Techniques

Which iterators does deque use, and why is it segmented?

deque chunks storage into fixed-size blocks with a map of block pointers, giving O(1) push at both ends with a random-access (but non-contiguous) memory model. Its iterator does two-level dereference — a classic "implement it on a whiteboard" question.

→ Deep dive: STL Source-Code Analysis: deque

5. Modern C++ (11/14/17/20)

What does std::move actually do?

Nothing at runtime: it's a cast to an rvalue reference that enables move constructor/assignment selection. The source is left valid-but-unspecified. Move semantics transfer resources (buffers, handles) instead of copying — the heart of modern C++ performance.

→ Deep dive: std::move: How It Works

auto and decltype — rules and pitfalls?

auto drops references and top-level const by value-deduction rules; decltype(expr) gives the declared type without the auto decay. Common trap: auto in range-for over a temporary container. decltype(auto) preserves the exact type.

→ Deep dive: C++ decltype

What changed with lambdas in modern C++?

Capture-by-value/reference with [], mutable, generic lambdas (C++14), constexpr lambdas and template parameter lists (C++20). Know what a captureless lambda converts to (function pointer) and why capturing lambdas can't.

→ Deep dive: std::bind vs lambda and C++20 Lambdas (Part 1)

Why does std::string_view exist and how do you shoot yourself in the foot with it?

Non-owning borrow of characters: cheap to pass, no allocation — but dangling views (returning a view of a temporary string) and the "may not be null-terminated" rule are the traps. Pass by value; never store beyond the owner's lifetime.

→ Deep dive: C++17 std::string_view

std::variant vs union vs inheritance?

variant is a type-safe sum type with an index and value-by-alternative access (std::get_if, std::visit); unions are unchecked; virtual inheritance adds heap indirection but open extension. Use variant for closed sets of states — the visitor pattern question often follows.

→ Deep dive: C++17 std::variant

What do Concepts fix compared to SFINAE?

Concepts (requires) make template constraints first-class, produce readable error messages, and participate in overload resolution — replacing the purpose-built SFINAE machinery (std::enable_if, expression SFINAE) for most cases.

→ Deep dive: C++20 Concepts

6. Templates and Generic Code

What is the two-phase lookup and the typename disambiguator?

Dependent names are looked up at instantiation; typename tells the parser that a dependent qualified name is a type (and template that it's a template) — required before C++20 relaxed some cases in function bodies.

→ Deep dive: STL Source-Code Analysis: typename and Template Disambiguation

Variadic templates: how do you process a parameter pack?

Recursion (base case + pack expansion) or fold expressions (C++17): (f(args), ...). Perfect forwarding with Args&&... + std::forward — the foundation of std::make_unique and emplace APIs.

→ Deep dive: Variadic Templates

7. Concurrency

std::thread vs std::jthread — why was the latter added?

jthread joins in its destructor (no terminate-on-destruction), and supports cooperative cancellation via std::stop_token. It fixes std::thread's two sharpest edges; prefer it in C++20 codebases.

→ Deep dive: std::thread & jthread and std::thread Internals

How do you debug a deadlock?

Deadlocks come from inconsistent lock ordering. Debug with GDB all-stop mode (see all threads' backtraces at the hang), TSan (-fsanitize=thread) or Helgrind for happens-before violations; fix with std::scoped_lock multi-lock acquisition, lock hierarchies, and timeout-based retry design.

→ Deep dive: Debugging Deadlocks · GDB Multi-Thread All-Stop · Helgrind Concurrency Checks

What is false sharing and how do you fix it?

When two threads write different variables that share one 64-byte cache line, coherence traffic serializes them. Fix with padding/alignas(64) (or std::hardware_destructive_interference_size). Symptom: parallel code that scales worse than serial — this is a favorite senior-level question.

→ Deep dive: False Sharing & Cache Lines

When does the C++17 parallel STL help — and when not?

std::execution::par parallelizes the 69 algorithms; wins when per-element work dominates scheduling overhead; beware iterator validity across threads and that par without unseq doesn't vectorize. Combine with SIMD for memory-bound loops.

→ Deep dive: C++17 Parallel STL and C++ SIMD Vectorization

8. C Interview Questions Every C++ Candidate Should Know

These C-language fundamentals still appear in C++ interviews (especially systems/embedded roles):

Also see the companion page std::string Interview Questions for string-specific deep dives (SSO, ABI compatibility, conversions).

How to Study From This List

  1. Answer out loud first, then read the deep dive — interviews grade explanation quality, not memorization.
  2. Follow the sections in order for systematic prep, or jump to your weakest area.
  3. Every deep dive compiles its examples against real STL/libstdc++ sources, so you can answer the "but how is it actually implemented?" follow-up.

Questions or want to discuss an answer? Open an issue on CPlusPlusThings or contact the author.

Комментарии