128 C++ Interview Questions and Answers (2026)

Blog / 128 C++ Interview Questions and Answers (2026)
C++

C++ isn't a legacy skill anymore — it's the engine behind the AI boom. More teams now ship Python APIs and ML backends on C++ for raw speed, so interviewers expect real fluency, not memorized buzzwords. Walk in shaky on ownership or move semantics and you'll lose the offer to someone who isn't.

This is 128 questions with tight, interview-ready answers and code where it counts. They're worked Junior to Mid to Senior, so you build from fundamentals up to the deep systems and concurrency questions. Work through them and you'll walk in ready to prove you actually know C++.

Q1.
What is the fundamental difference between a reference and a pointer in C++? Can a reference be null?

Junior

A reference is an alias for an existing object that must be bound at initialization and can never be rebound or be null; a pointer is an independent object holding an address that can be null, reassigned, and have arithmetic applied. No, a well-formed reference cannot be null.

  • Binding and reseating:

    • A reference must be initialized when declared and stays bound to that object for its lifetime.

    • A pointer can be left uninitialized, set to nullptr, and pointed at different objects over time.

  • Nullability:

    • References have no null state in valid code; binding one to a dereferenced null pointer is undefined behavior.

    • Pointers explicitly model "no object" with nullptr.

  • Syntax and semantics:

    • A reference is used like the object itself (no * or ->); pointers need dereferencing and support pointer arithmetic.

    • Rule of thumb: use a reference when the object always exists, a pointer when absence or rebinding is meaningful.

Q2.
What is a dangling pointer, and how does modern C++ (C++11 and later) provide tools to avoid them?

Junior

A dangling pointer is one that still holds an address whose underlying object has already been destroyed or freed, so dereferencing it is undefined behavior. Modern C++ reduces them by encoding ownership and lifetime in types like smart pointers rather than relying on manual delete.

  • How they arise: Using a pointer after delete, returning the address of a local, or keeping a pointer into a container that reallocated.

  • RAII smart pointers: std::unique_ptr and std::shared_ptr tie deletion to scope/refcount, so you don't leave a raw pointer to freed memory.

  • Observing without owning: std::weak_ptr lets you check if a shared_ptr-managed object is still alive via lock() before use.

  • Move semantics: Moving a unique_ptr nulls the source, avoiding two owners that could double-free.

  • Still your responsibility: Smart pointers don't fix dangling raw references or iterators; tools like sanitizers (ASan) catch those at runtime.

Q3.
What is a memory leak, and how do smart pointers help prevent them?

Junior

A memory leak is heap memory that is allocated but never freed because the program loses every reference to it, so it stays reserved until the process ends. Smart pointers prevent this by binding deallocation to ownership and scope (RAII), removing the need for manual delete.

  • How leaks happen: Forgetting delete, an early return or exception skipping cleanup, or overwriting the only pointer to a block.

  • How smart pointers help:

    • unique_ptr frees its object automatically when it goes out of scope, even on exceptions.

    • shared_ptr frees when the last owner is destroyed, so cleanup happens exactly once.

  • Limits:

    • shared_ptr cycles still leak: break them with weak_ptr.

    • Prefer make_unique/make_shared and avoid raw owning pointers entirely.

Q4.
Why can't we copy a std::unique_ptr, but we can move it?

Junior

Because std::unique_ptr models exclusive ownership: only one pointer may own the resource at a time. Copying would create two owners of the same heap object, leading to a double-free; moving transfers ownership and leaves the source empty.

  • Copy is deleted by design:

    • The copy constructor and copy assignment of unique_ptr are = delete, so the compiler rejects any copy attempt.

    • If copying were allowed, both copies would call delete on the same pointer in their destructors: undefined behavior.

  • Move transfers ownership:

    • The move constructor copies the raw pointer out and sets the source's pointer to nullptr, so exactly one owner remains.

    • The moved-from unique_ptr is valid but empty (deleting nothing in its destructor).

  • You must opt into moving: Use std::move to pass ownership, since a named lvalue won't bind to the move constructor on its own.

cpp

std::unique_ptr<int> a = std::make_unique<int>(42); // std::unique_ptr<int> b = a; // error: copy deleted std::unique_ptr<int> b = std::move(a); // ok: ownership moved, a is now null

Q5.
What is the difference between a const pointer and a pointer to const?

Junior

A pointer to const protects the pointed-to data (you can't change the value through it, but you can repoint it); a const pointer fixes the pointer itself (it always points at the same address, but you may modify the value). Read the declaration right-to-left.

  • Pointer to const: const int* p:

    • *p = 5; is illegal; p = &other; is legal.

    • Same as int const* p.

  • Const pointer: int* const p: *p = 5; is legal; p = &other; is illegal (must be initialized at declaration).

  • Const pointer to const: const int* const p: Neither the value nor the pointer can change.

cpp

int a = 1, b = 2; const int* p1 = &a; // can't change *p1, can change p1 p1 = &b; // ok int* const p2 = &a; // can change *p2, can't change p2 *p2 = 9; // ok

Q6.
What is the difference between a shallow copy and a deep copy? Give a scenario where a shallow copy causes a crash.

Junior

A shallow copy duplicates the object's members bit-for-bit, so pointer members in both objects point to the same underlying resource; a deep copy allocates and copies the pointed-to resource too, giving each object its own independent copy. Shallow copies of owning pointers cause double-free crashes.

  • Shallow copy:

    • Member-wise copy: the default compiler-generated copy constructor and copy assignment.

    • Fine for value-only members; dangerous when a member owns heap memory.

  • Deep copy: Custom copy constructor/assignment allocates new storage and copies the contents, so the objects don't share state.

  • Crash scenario:

    • A class holds a raw int* to heap memory it deletes in its destructor.

    • Shallow-copy it: two objects hold the same pointer. When both destruct, the memory is deleted twice (double free): undefined behavior, typically a crash.

  • Rule of three / five: If you write a destructor, you likely need a copy constructor and copy assignment too (and move versions in modern C++). Better: hold a unique_ptr or vector so copy semantics are correct by default.

Q7.
What does it mean for a class method to be marked as const? Can a const method modify any member variables?

Junior

Marking a method const promises it won't modify the object's observable state, so it can be called on const objects and references. Inside it, this is a pointer to const, so member variables are read-only, with two deliberate exceptions.

  • What const enforces:

    • You cannot assign to non-mutable members or call non-const methods from within it.

    • It lets const instances be used and enables const-correct APIs.

  • Exceptions (yes, it can modify some members):

    • mutable members can be changed even in a const method (caches, mutexes, lazy-computed values).

    • It only protects this's direct members. If a member is a pointer, the pointee can still be modified (the pointer is const, not what it points to).

  • Const overloading: You can provide both a const and non-const version of a method; the compiler picks based on the object's constness.

cpp

class Widget { int value = 0; mutable int cache = 0; public: int get() const { cache++; /* ok: mutable */ return value; } // void set(int v) const { value = v; } // error: value not mutable };

Q8.
What is the difference between struct and class in C++ beyond the default access specifier?

Junior

The only language-level difference is the default access: members and base-class inheritance are public in a struct and private in a class. Otherwise they are fully interchangeable: both can have methods, constructors, inheritance, access specifiers, and templates.

  • Default member access:

    • struct: members default to public.

    • class: members default to private.

  • Default inheritance access: struct B : A is public inheritance; class B : A is private inheritance.

  • Everything else is identical: Both support methods, virtual functions, access control, templates, and constructors/destructors.

  • Conventional usage (not enforced): struct is typically used for passive aggregates of public data (POD-like); class for types with invariants and encapsulation.

Q9.
What is a member initializer list, and why is it preferred over assignment in the constructor body?

Junior

A member initializer list is the : member(value), ... syntax after the constructor signature that initializes members directly, before the constructor body runs. It's preferred because it constructs each member once, instead of default-constructing then reassigning.

  • Initialization vs. assignment:

    • In the list, the member is built with the given value in one step.

    • In the body, the member is already default-constructed, then operator= overwrites it: two operations, often wasteful.

  • When it's mandatory:

    • const members and reference members: they can only be initialized, never assigned.

    • Members with no default constructor, and base-class subobjects.

  • Gotcha: order: Members initialize in declaration order, not the order written in the list; mismatches can cause use-before-init bugs.

cpp

class Point { const int id; int x, y; public: Point(int i, int a, int b) : id(i), x(a), y(b) {} // id MUST be here; others built once };

Q10.
Explain the difference between the stack and the heap. When would you prefer one over the other?

Junior

The stack is fast, automatically managed memory for local variables with LIFO lifetime; the heap is a larger, manually (or smart-pointer) managed pool for objects whose size or lifetime isn't known at compile time. Prefer the stack for short-lived, fixed-size data and the heap when you need dynamic size or lifetime beyond the current scope.

  • The stack:

    • Allocation is just moving a pointer, so it's extremely fast; memory is reclaimed automatically when scope ends.

    • Limited in size (typically a few MB); deep recursion or huge arrays cause stack overflow.

  • The heap:

    • Allocated via new/malloc; survives until explicitly freed, so it outlives the creating function.

    • Slower (bookkeeping, possible fragmentation) and risks leaks/dangling pointers if mismanaged.

  • When to prefer which:

    • Stack: size known at compile time, lifetime confined to the scope.

    • Heap: large or runtime-sized data, ownership transfer, or lifetime extending past the function; wrap it in unique_ptr/shared_ptr.

Q11.
What is an abstract class, and how do you create one in C++?

Junior

An abstract class is one that cannot be instantiated on its own because it declares at least one pure virtual function; it exists to define a common interface that derived classes must complete.

  • How to create one: Declare at least one pure virtual function using = 0, e.g. virtual void draw() = 0;.

  • Rules:

    • You cannot create an object of it directly, but you can have pointers/references to it for polymorphism.

    • A derived class stays abstract until it overrides all inherited pure virtual functions.

    • It may still have constructors, data members, and even a definition for a pure virtual function (callable explicitly).

  • Always give it a virtual destructor since it is a polymorphic base.

cpp

class Shape { public: virtual double area() const = 0; // pure virtual -> abstract virtual ~Shape() = default; }; // Shape s; // error: cannot instantiate abstract class

Q12.
What is the purpose of the override and final keywords?

Junior

Both are C++11 contextual keywords that make virtual-function intent explicit and let the compiler catch mistakes: override asserts that a function really overrides a base virtual, and final forbids further overriding (on a function) or further derivation (on a class).

  • override:

    • Compile error if the function does not match a base virtual (wrong name, signature, or constness), catching silent bugs where you accidentally create a new function instead of overriding.

    • Documents intent and improves readability.

  • final:

    • On a virtual function: prevents any derived class from overriding it further.

    • On a class: prevents inheriting from that class at all.

    • Can enable devirtualization optimizations, since the compiler knows the call target is fixed.

  • Note: They are not reserved words: they only have meaning in these specific positions, so existing identifiers named override still work.

cpp

struct Base { virtual void f(); }; struct Derived : Base { void f() override; // verified against Base::f void g() final; // (if g were virtual) no further override }; struct Last final : Derived {}; // Last cannot be a base class

Q13.
What is the difference between a virtual function and a pure virtual function?

Junior

A virtual function provides a default implementation that derived classes may override; a pure virtual function (declared = 0) provides no implementation and forces derivation, making its class abstract.

  • Virtual function: Has a body; the base is fully instantiable and the derived class can optionally override it.

  • Pure virtual function:

    • Declared with = 0; makes the class abstract so it cannot be instantiated directly.

    • Any concrete derived class must override every pure virtual or it too stays abstract.

  • Note: A pure virtual can still have a definition you call explicitly, but the = 0 still forces overriding.

cpp

struct Shape { virtual double area() const = 0; // pure virtual -> abstract virtual void draw() const { /*...*/ } // virtual with default }; struct Circle : Shape { double area() const override { return 3.14159 * r * r; } double r; };

Q14.
What is the difference between std::set, std::multiset, and std::unordered_set?

Junior

All three store keys, but std::set keeps unique keys in sorted order, std::multiset keeps sorted keys but allows duplicates, and std::unordered_set keeps unique keys with no ordering using a hash table.

  • std::set:

    • Balanced BST: elements sorted by comparator, all unique.

    • O(log n) insert/find/erase; supports ordered traversal and range queries (lower_bound).

  • std::multiset:

    • Same sorted, tree-based structure but permits multiple equal keys.

    • Useful when counting/keeping duplicates matters; count() can exceed 1.

  • std::unordered_set:

    • Hash table: unique keys, no defined order.

    • Average O(1) insert/find/erase, worst case O(n); requires a hash and operator== rather than an ordering.

  • Choosing: need ordering or range queries, use std::set; need duplicates too, std::multiset; need fastest average lookup and order is irrelevant, std::unordered_set.

Q15.
What is the difference between an enum and an enum class (scoped enumeration)?

Junior

A scoped enumeration (enum class) fixes the safety problems of a plain enum: it doesn't leak its enumerators into the surrounding scope and doesn't implicitly convert to integers.

  • Scope of enumerators: Plain enum names go into the enclosing scope, risking name clashes; enum class names are accessed as Color::Red.

  • Implicit conversion: A plain enum converts silently to int (error-prone in comparisons/arithmetic); a scoped enum requires an explicit static_cast.

  • Underlying type: Both can specify it (e.g. enum class E : std::uint8_t); scoped enums default to int, giving predictable size and forward declaration.

  • Rule of thumb: prefer enum class by default for type safety; use plain enum only for legacy/bit-flag interop convenience.

cpp

enum class Color { Red, Green }; Color c = Color::Red; // int x = c; // error: no implicit conversion int x = static_cast<int>(c); // explicit, intentional

Q16.
Explain the difference between a process and a thread. How do they share memory in a C++ application?

Junior

A process is an independent program with its own private virtual address space; a thread is a unit of execution that runs inside a process. Threads of the same process share that address space, so they share memory by default, while processes are isolated.

  • Process:

    • Owns its address space, file descriptors, and resources; crashing one usually doesn't affect others.

    • Inter-process communication needs explicit mechanisms (pipes, sockets, shared memory segments).

  • Thread:

    • Has its own stack and registers but shares heap, globals, and code with sibling threads.

    • Created in C++ via std::thread / std::jthread; cheaper to create and switch than a process.

  • Sharing memory in C++:

    • Threads access the same heap objects and globals directly, which is why synchronization (std::mutex, std::atomic) is required to avoid data races.

    • Unsynchronized concurrent access where at least one is a write is undefined behavior.

Q17.
Explain the difference between function overloading and function overriding.

Junior

Overloading is having multiple functions with the same name but different parameter lists, resolved at compile time; overriding is a derived class replacing a base class's virtual function with its own implementation, resolved at runtime.

  • Function overloading:

    • Same scope, same name, different signatures (number/types of parameters). Return type alone does not count.

    • Resolved by the compiler via overload resolution (static/compile-time polymorphism).

  • Function overriding:

    • Requires inheritance and a virtual function in the base; the derived signature must match.

    • Dispatched at runtime through the vtable (dynamic polymorphism) based on the object's actual type.

    • Use override so the compiler verifies you really are overriding and not silently creating a new function.

  • Key contrast: Overloading is about choosing among siblings at compile time; overriding is about choosing the right derived behavior through a base pointer/reference at runtime.

cpp

struct Base { void f(int); // overload void f(double); // overload virtual void g(); // can be overridden }; struct Derived : Base { void g() override; // override };

Q18.
What is the difference between pass by value, pass by reference, and pass by pointer?

Junior

Pass by value copies the argument into the parameter; pass by reference gives the function an alias to the caller's variable; pass by pointer passes the address, so the function works through it. References and pointers let the callee modify the original and avoid copying; the difference is mainly syntax and nullability.

  • Pass by value:

    • Callee gets its own copy; changes don't affect the caller. Safe but can be expensive for large objects.

    • For read-only large objects prefer const T& to skip the copy.

  • Pass by reference:

    • An alias to the original (T&); modifications are visible to the caller and no copy is made.

    • Cannot be null and cannot be reseated; cleaner syntax (obj.method() not ptr->method()).

  • Pass by pointer:

    • Passes an address (T*); can be null to mean optional, and can be made to point elsewhere.

    • Requires dereferencing and a null check; common in C-style and ownership-transfer code.

  • Rule of thumb: Default to const T& for non-trivial inputs, by value for small/cheap types, and a pointer when null is a meaningful value.

Q19.
What is the difference between a declaration and a definition in C++?

Junior

A declaration introduces a name and its type to the compiler; a definition additionally provides the full implementation or allocates storage. Every definition is also a declaration, but not every declaration is a definition.

  • Declaration:

    • Tells the compiler a name exists and what type it has, e.g. int f(int); or extern int x;.

    • You can declare the same entity multiple times.

  • Definition:

    • Provides the body or storage, e.g. int f(int){...} or int x;.

    • Subject to the One Definition Rule (ODR): exactly one definition across the program (except for inline functions and templates).

  • Practical impact:

    • Headers usually carry declarations; source files carry definitions, enabling separate compilation.

    • A missing definition produces a linker error (unresolved symbol), not a compiler error.

Q20.
What is the purpose of header guards (#ifndef) versus #pragma once?

Junior

Both prevent a header's contents from being included more than once in a single translation unit, which would cause redefinition errors. Header guards use standard preprocessor macros; #pragma once is a non-standard but widely supported compiler directive that does the same thing more conveniently.

  • Header guards (#ifndef):

    • Wrap the file in #ifndef X / #define X / #endif so the body compiles only once.

    • Fully portable (standard C++), but you must pick a unique macro name or risk collisions.

  • #pragma once:

    • One line, no macro to invent, and the compiler tracks files by identity.

    • Non-standard (though supported by all major compilers) and can misbehave with odd filesystems, symlinks, or copied files.

  • Rule of thumb: Use #pragma once for convenience; prefer (or combine with) guards when strict portability matters.

cpp

#ifndef MY_WIDGET_H #define MY_WIDGET_H // ... declarations ... #endif // equivalent, simpler: #pragma once // ... declarations ...

Q21.
Why is std::endl often considered slower than using \n?

Junior

std::endl does two things: it inserts a newline AND flushes the stream's buffer, whereas '\n' only inserts the newline. The forced flush is the expensive part, since each flush can trigger a system call and defeats buffering.

  • What each does:

    • std::endl is equivalent to writing '\n' then calling flush().

    • '\n' just appends a newline and lets the buffer flush naturally.

  • Why the flush hurts:

    • In a loop printing many lines, std::endl forces a flush every iteration, turning buffered output into many small writes.

    • Buffering exists precisely to batch I/O, so repeated flushing throws that benefit away.

  • When endl is fine:

    • When you actually need the output visible immediately (e.g. before a crash, or interactive prompts).

    • Default to '\n' and flush explicitly only when required.

Q22.
Why is it generally recommended to avoid 'using namespace std;' in header files?

Junior

Because a header is textually included into every file that uses it, a using namespace std; in a header forces that namespace into every translation unit, silently polluting the global namespace of code you don't control and risking name collisions and ambiguity.

  • It leaks everywhere: Every file that includes the header (directly or transitively) inherits the directive; clients can't opt out.

  • It causes name collisions:

    • Common names like count, distance, or swap can clash with user code, producing surprising ambiguity errors.

    • Overload resolution can silently pick a different function than intended, changing behavior.

  • Better practices:

    • In headers, always qualify fully (std::vector, std::string).

    • If needed, limit a using-declaration to a single name inside a function scope in a .cpp file, never at header global scope.

Q23.
How does std::shared_ptr work, and how is the reference counter synchronized between objects?

Mid

std::shared_ptr implements shared ownership through a separately allocated control block that holds a strong reference count; the last owner to release brings the count to zero and destroys the object. The counts are stored in that shared control block and updated with atomic operations so reference-count changes are thread-safe.

  • The control block:

    • Holds the strong count, the weak count, the managed pointer, and the deleter/allocator.

    • Every shared_ptr to the object points to the same control block.

  • Counting behavior:

    • Copying increments the strong count; destruction or reset decrements it.

    • At strong count 0 the managed object is destroyed; the control block lives until the weak count also hits 0.

  • Synchronization:

    • The reference count is modified atomically, so copying/destroying shared_ptrs to the same object from multiple threads is safe.

    • Important caveat: only the count is synchronized, not the pointee or the shared_ptr instance itself; concurrent writes to the managed object still need your own locking.

Q24.
What is the difference between std::make_shared<T> and std::shared_ptr<T>(new T) in terms of heap allocations and exception safety?

Mid

std::make_shared<T> allocates the object and its control block together in a single heap allocation and is exception-safe, while std::shared_ptr<T>(new T) performs two allocations and can leak in certain expression-evaluation orderings.

  • Allocation count:

    • make_shared: one allocation for object + control block, improving locality and reducing overhead.

    • shared_ptr<T>(new T): one allocation for the object, a second for the control block.

  • Exception safety:

    • With separate new, in calls like f(shared_ptr<T>(new T), g()) the compiler may run new T then g() (which throws) before the shared_ptr is constructed, leaking the object.

    • make_shared constructs the owner in one step, so there's no unmanaged window.

  • Trade-off:

    • With make_shared the single block lives as long as any weak_ptr, so the object's memory isn't freed until all weak refs die.

    • It also can't use a custom deleter; for that, use the new form.

Q25.
How does std::weak_ptr help in solving the circular dependency problem, and what happens internally when you call .lock() on it?

Mid

std::weak_ptr is a non-owning observer of a shared_ptr-managed object: it breaks reference cycles by not contributing to the strong count, so two objects can refer to each other without keeping each other alive. Calling .lock() atomically tries to promote the weak reference into a strong shared_ptr.

  • The cycle problem:

    • If A holds a shared_ptr to B and B holds one back to A, their strong counts never reach 0 and both leak.

    • Making one direction a weak_ptr lets the cycle be destroyed.

  • What lock() does internally:

    • It checks the strong count in the control block; if greater than 0, it atomically increments it and returns a valid shared_ptr.

    • If the object is already destroyed (strong count 0), it returns an empty shared_ptr.

  • Weak count role: Each weak_ptr keeps the control block (not the object) alive via the weak count, so expired() and lock() remain safe to query.

Q26.
What is the difference between std::unique_ptr, std::shared_ptr, and std::weak_ptr?

Mid

The three differ by ownership model: unique_ptr is sole ownership, shared_ptr is shared ownership via reference counting, and weak_ptr is a non-owning observer of a shared_ptr.

  • std::unique_ptr:

    • Exactly one owner; move-only, not copyable.

    • Zero overhead (pointer-sized with default deleter); the default choice for owned heap objects.

  • std::shared_ptr:

    • Many owners share one object; a control block tracks the atomic strong count.

    • Object is destroyed when the last owner releases; costs space and atomic ops.

  • std::weak_ptr:

    • Observes a shared_ptr without affecting its strong count, so it can't keep the object alive.

    • Use lock() to get a usable shared_ptr; breaks reference cycles and detects dangling.

  • Choosing: Default to unique_ptr; reach for shared_ptr only when ownership is genuinely shared; use weak_ptr for back-references and caches.

Q27.
What are the different ways to access private fields of a class from outside that class?

Mid

Private access is a compile-time encapsulation boundary, not runtime protection. The sanctioned routes are friendship and member access from within the class; the rest are deliberate workarounds or undefined-behavior hacks you'd only mention to show you understand the model.

  • Legitimate ways:

    • friend functions or friend classes are explicitly granted access by the class.

    • Public accessor methods (getters/setters) provided by the class itself.

    • Member functions and the class's own nested types can access private members.

  • Loophole / abuse routes:

    • Explicit template instantiation tricks (the well-known 'access private member via pointer-to-member in an explicit instantiation' technique) bypass access checks legally per the standard.

    • #define private public before including a header: works but is undefined behavior across translation units and fragile.

    • Casting/raw memory access: computing the member's offset and reading it via reinterpret_cast. This is UB and breaks with layout changes.

  • Key insight: private prevents accidental access at compile time; it is not a security mechanism against a determined caller.

Q28.
How can you protect a class object from being copied? Explain the difference between deleting the copy constructor and making it private.

Mid

Suppress the copy operations so the class can't be duplicated. The modern way is = delete on the copy constructor and copy assignment; the old C++98 way was declaring them private with no definition. Both block copying, but = delete fails earlier and clearer.

  • Deleting the copy members (preferred, C++11+):

    • Any copy attempt is a compile-time error with a clear 'use of deleted function' message.

    • Applies to everyone, including friends and member functions: there is no copy at all.

  • Making them private with no body (old idiom):

    • Outside code gets an access error; but a member or friend could still call it, and the error only surfaces at link time (no definition) rather than compile time.

    • Diagnostics are worse and the intent is less obvious.

  • Remember move operations: Declaring/deleting copy operations suppresses implicit move generation, so a class with deleted copy is also non-movable unless you define moves explicitly.

cpp

class NonCopyable { public: NonCopyable() = default; NonCopyable(const NonCopyable&) = delete; NonCopyable& operator=(const NonCopyable&) = delete; };

Q29.
What is the 'explicit' keyword and why is it used for constructors?

Mid

The explicit keyword prevents a constructor (or conversion operator) from being used for implicit conversions, so the compiler won't silently turn a value into your type behind your back.

  • The problem it solves: A single-argument constructor doubles as an implicit conversion: String s = 10; would build a 10-char string when you likely meant something else.

  • What explicit does:

    • Forces callers to construct the object directly (String s(10);), banning the surprising implicit form.

    • Also blocks copy-initialization and implicit conversions in function arguments.

  • Where to use it:

    • Default to marking single-argument constructors explicit unless the implicit conversion is genuinely desirable.

    • Since C++11 it applies to multi-arg constructors (via brace lists) and conversion operators too.

cpp

struct Widget { explicit Widget(int n); }; Widget a(5); // OK: direct init Widget b = 5; // ERROR: implicit conversion blocked void f(Widget); f(5); // ERROR: no silent int -> Widget

Q30.
What does the 'mutable' keyword do in C++?

Mid

The mutable keyword lets a data member be modified even when the enclosing object is const, so logical constness can differ from bitwise constness.

  • Bypasses const on a per-member basis: A mutable member can be written inside a const member function and through a const reference/pointer to the object.

  • Typical use cases:

    • Caching/memoization: a cached result the const observer fills in lazily.

    • Internal bookkeeping: mutexes (mutable std::mutex), hit counters, lazy-computed flags that don't change the object's observable value.

  • Caveat: Use it for things that don't affect the object's logical state; abusing it to mutate real state breaks the const contract and surprises callers.

cpp

class Cache { mutable bool valid = false; mutable int result = 0; public: int get() const { // const, yet can update cache if (!valid) { result = compute(); valid = true; } return result; } };

Q31.
Explain the difference between new/delete and malloc/free.

Mid

Both allocate raw memory, but new/delete are type-aware C++ operators that also run constructors and destructors, while malloc/free are C library functions that only manage bytes.

  • Object lifetime:

    • new constructs the object; delete calls its destructor before freeing.

    • malloc returns uninitialized memory and free runs no destructor.

  • Type and size: new returns the correct typed pointer and computes size automatically; malloc takes a byte count and returns void* needing a cast.

  • Failure behavior:

    • new throws std::bad_alloc on failure (unless nothrow); malloc returns nullptr.

    • new can be customized/overloaded; malloc cannot.

  • Never mix them: free-ing a newed pointer (or vice versa) is undefined behavior; in modern C++ prefer smart pointers over either.

Q32.
Explain the different storage classes in C++ (auto, register, static, extern) and where they are stored in the memory map.

Mid

Storage classes specify a variable's lifetime (storage duration) and linkage/visibility. The classic specifiers are auto, register, static, and extern, and they map onto the program's memory regions (stack, registers, and the static data segment).

  • auto:

    • Originally meant automatic (stack) storage for locals: the default, so the keyword was redundant.

    • Since C++11 auto was repurposed for type deduction and no longer means a storage class.

  • register:

    • A hint to keep the variable in a CPU register for speed; you can't take its address.

    • Always just a hint, now deprecated/removed: modern compilers ignore it and optimize themselves.

  • static:

    • Gives static storage duration (lives for the whole program) and lives in the data/BSS segment.

    • At file scope it also gives internal linkage (file-private); on a local it preserves value between calls.

  • extern:

    • Declares a name with external linkage defined elsewhere, so multiple translation units share one object.

    • It's a declaration, not a definition: the storage lives in the data segment of whichever unit defines it.

  • Memory map summary: Locals: stack; register: (ideally) a CPU register; static/extern objects: initialized data or zero-initialized BSS segment.

Q33.
What are alignment and padding, and how do they affect the size of a struct?

Mid

Alignment is the requirement that an object's address be a multiple of some value (often its size); padding is the unused filler bytes the compiler inserts between or after members so each one is properly aligned. Together they can make a struct larger than the sum of its members.

  • Why alignment exists: Hardware reads memory most efficiently (or only correctly) when types sit on natural boundaries: a 4-byte int on a 4-byte boundary.

  • Where padding appears:

    • Between members, to push the next member to its alignment.

    • At the end (tail padding), so the struct's size is a multiple of its largest member's alignment (important for arrays).

  • Member order matters: Ordering members from largest to smallest minimizes padding and shrinks the struct.

  • Control and inspection: alignof queries alignment, alignas sets it, and #pragma pack can reduce padding (at a performance/portability cost).

cpp

struct Bad { char c; int i; char d; }; // size 12: padding around c and d struct Good { int i; char c; char d; }; // size 8: members reordered // assumes 4-byte int alignment

Q34.
What happens under the hood when you call delete vs. delete[]? Why is it undefined behavior to mix them?

Mid

delete destroys a single object then frees its memory, while delete[] destroys every element of an array (in reverse order) then frees it. Mixing them with the wrong form of new is undefined behavior because the runtime tracks array allocations differently.

  • What each does:

    • delete p: calls ~T() once, then releases the block.

    • delete[] p: calls ~T() on each element, then releases the block.

  • How the count is known:

    • new[] often stores the element count (a cookie) just before the returned pointer so delete[] knows how many destructors to run.

    • new has no such cookie; the two allocation shapes are not interchangeable.

  • Why mixing is UB:

    • delete on an array pointer skips most destructors and may free from the wrong address (ignoring the cookie), corrupting the heap.

    • delete[] on a single object reads a count that isn't there.

  • Practical advice: Match the form to the new; better yet use std::vector or std::unique_ptr<T[]> to remove the choice entirely.

Q35.
What is the 'Diamond Problem' in multiple inheritance, and how does C++ solve it?

Mid

The Diamond Problem arises when a class inherits from two classes that both derive from a common base, creating two copies of that base's members and ambiguity about which to use; C++ solves it with virtual inheritance, which keeps a single shared subobject.

  • The setup: Class D inherits from B and C, both deriving from A. Without intervention, D contains two A subobjects.

  • The problem: Accessing an inherited A member through D is ambiguous (which copy?), and storing two copies wastes space and can desync state.

  • The fix: virtual inheritance:

    • Declare class B : virtual public A and class C : virtual public A so D gets exactly one shared A.

    • The most-derived class (D) is responsible for initializing the virtual base's constructor.

  • Cost: Virtual bases add a pointer/offset indirection to reach the shared subobject, so use only when truly needed.

cpp

struct A { int x; }; struct B : virtual public A {}; struct C : virtual public A {}; struct D : public B, public C {}; // single shared A D d; d.x = 5; // unambiguous: one A subobject

Q36.
Why do we need a virtual destructor in a base class? What happens if you delete a derived class object through a base class pointer without one?

Mid

A base class needs a virtual destructor so that deleting a derived object through a base pointer invokes the correct derived destructor chain; without it the behavior is undefined and typically only the base part is destroyed, leaking resources.

  • What goes wrong without it:

    • delete basePtr; with a non-virtual destructor is undefined behavior; in practice the compiler statically calls only ~Base(), skipping ~Derived().

    • Derived-only resources (heap memory, file handles) never get released.

  • Why virtual fixes it: A virtual destructor is dispatched through the vtable at runtime, so the actual dynamic type's destructor runs first, then bases in reverse order.

  • Rule of thumb:

    • Give any class meant to be a polymorphic base (deleted via base pointer) a virtual destructor.

    • If a class is never used polymorphically, a virtual destructor just adds a vptr overhead for no benefit.

cpp

struct Base { virtual ~Base() = default; }; struct Derived : Base { ~Derived() { /* frees resources */ } }; Base* p = new Derived(); delete p; // virtual dtor -> ~Derived() then ~Base() run correctly

Q37.
Explain the concept of vtable and vptr. How does the compiler resolve a virtual function call at runtime?

Mid

The vtable is a per-class array of pointers to that class's virtual functions, and the vptr is a hidden per-object pointer to its class's vtable; a virtual call is resolved by following the vptr to the vtable and indexing the correct slot at runtime (dynamic dispatch).

  • vtable (one per class): Built by the compiler for any class with virtual functions; each slot points to the most-derived override for that class.

  • vptr (one per object): A hidden member set by the constructor to point at the dynamic type's vtable; this is why type identity is correct at runtime.

  • How a call resolves:

    1. Load the object's vptr.

    2. Index into the vtable at the function's fixed slot.

    3. Call the function pointer found there.

  • Key consequences:

    • It is an implementation detail (not in the standard), but virtually all compilers use it.

    • Non-virtual calls are resolved at compile time (static binding); only virtual calls use this indirection.

    • During construction/destruction the vptr reflects the class currently being built, so virtual calls in a constructor don't dispatch to derived overrides.

Q38.
What is the difference between an abstract class and an interface in C++? How do you implement an interface in C++?

Mid

C++ has no dedicated interface keyword: an interface is simply an abstract class with only pure virtual functions and no data, while a general abstract class may also contain data members and implemented methods. You implement an interface by inheriting from such a pure-virtual class and overriding every method.

  • Abstract class: Has at least one pure virtual function (= 0) but may also hold state and provide concrete methods, giving partial implementation.

  • Interface (a convention): A pure abstract class: all functions pure virtual, no data members, plus a virtual destructor. It is a pure contract.

  • Implementing one: Publicly inherit and override every pure virtual method; multiple interfaces can be combined since C++ allows multiple inheritance.

cpp

struct IShape { // interface virtual double area() const = 0; virtual ~IShape() = default; }; struct Circle : IShape { // implements the interface double r; explicit Circle(double r) : r(r) {} double area() const override { return 3.14159 * r * r; } };

Q39.
Explain the difference between public, protected, and private inheritance.

Mid

The inheritance access specifier controls the maximum visibility that base class members get in the derived class: public preserves their access, protected caps everything at protected, and private caps everything at private. In all cases the base's own private members remain inaccessible.

  • public inheritance ("is-a"): Base public stays public, protected stays protected; the natural choice for subtype polymorphism.

  • protected inheritance: Base public and protected members become protected in the derived class: accessible to it and its further descendants, but not outside.

  • private inheritance ("implemented-in-terms-of"): All accessible base members become private; outside code cannot use the base interface and cannot convert the derived to the base.

  • Key effect:

    • Only public inheritance allows an implicit Derived*-to-Base* conversion, so it is what enables true polymorphic use; protected/private model composition/reuse.

    • Default is private for class and public for struct.

Q40.
Can a constructor be virtual in C++? Why or why not?

Mid

No, a constructor cannot be virtual. Virtual dispatch relies on the vptr, which is set up during construction, so the object's type isn't established yet when the constructor runs; there is also nothing to dispatch on since you must already name a concrete type to construct it.

  • Why it's impossible:

    • Virtual calls need a fully formed vptr, but the constructor is what initializes that vptr: a chicken-and-egg situation.

    • To construct an object you state its exact type explicitly, so runtime polymorphism over the constructor is meaningless.

  • What you do instead: The virtual constructor idiom: a virtual clone() method that returns a copy of the dynamic type, or a virtual create() factory method.

  • Related: Destructors can and often should be virtual, because by then the object is fully constructed and its type is known.

cpp

struct Base { virtual Base* clone() const { return new Base(*this); } virtual ~Base() = default; }; struct Derived : Base { Derived* clone() const override { return new Derived(*this); } }; // virtual-constructor idiom: copy without knowing the concrete type

Q41.
What are the tradeoffs of using composition over inheritance?

Mid

Composition models a "has-a" relationship by holding member objects, giving looser coupling and runtime flexibility than inheritance's rigid "is-a" hierarchy, at the cost of some boilerplate forwarding.

  • Benefits of composition:

    • Looser coupling: you depend on a component's public interface, not its internals.

    • Flexibility: components can be swapped at runtime (especially via interfaces), enabling strategy-like designs.

    • Avoids the fragile base class problem and deep, brittle hierarchies.

  • Costs of composition:

    • Boilerplate: you may write forwarding methods to expose the component's behavior.

    • No automatic subtype polymorphism: a composed object is not substitutable for its parts unless you add an explicit interface.

  • Rule of thumb: Use inheritance only for genuine "is-a" with substitutability; otherwise prefer composition.

Q42.
Explain Object Slicing and how it occurs when passing objects by value in an inheritance hierarchy.

Mid

Object slicing happens when a derived object is copied into a base-class object by value: only the base subobject is copied and the derived-specific data and dynamic type are "sliced off," so virtual dispatch no longer reaches the derived behavior.

  • Why it occurs:

    • A by-value base parameter or variable has the exact size of the base, so there is no room for derived members.

    • The copy invokes the base copy constructor, which knows nothing about the derived part.

  • Consequence: The static type becomes the base, so even virtual calls run the base version, not the overridden one.

  • How to avoid it: Pass and store polymorphic objects by reference (const Base&) or pointer (including smart pointers).

cpp

struct Base { virtual void who() { std::cout << "Base"; } }; struct Derived : Base { void who() override { std::cout << "Derived"; } }; void byValue(Base b) { b.who(); } // sliced: always prints "Base" void byRef(Base& b) { b.who(); } // polymorphic: prints "Derived" Derived d; byValue(d); // Base byRef(d); // Derived

Q43.
What is the difference between compile-time and runtime polymorphism?

Mid

Compile-time (static) polymorphism resolves which function to call during compilation; runtime (dynamic) polymorphism defers that decision until execution using the object's actual type via virtual dispatch.

  • Compile-time polymorphism:

    • Achieved with function overloading, operator overloading, and templates.

    • No runtime overhead and fully inlinable, but the type must be known at compile time.

  • Runtime polymorphism:

    • Achieved with virtual functions and base-class pointers/references.

    • Dispatch goes through a vtable, costing a small indirection but enabling true subtype flexibility.

  • Trade-off: Static = faster and resolved early; dynamic = flexible and decoupled, chosen when behavior depends on the runtime type.

Q44.
What is the order of construction and destruction of objects in an inheritance hierarchy?

Mid

Construction runs base-to-derived (bases first, then members, then the derived body), and destruction runs in the exact reverse order, derived-to-base.

  • Construction order:

    1. Base class constructors, in the order bases are listed in the inheritance declaration.

    2. Non-static member objects, in their declaration order (not initializer-list order).

    3. The derived class's own constructor body.

  • Destruction order: Exactly reversed: derived body, then members, then base destructors.

  • Key consequence:

    • Deleting via a base pointer requires a virtual destructor, or the derived part won't be destroyed (undefined behavior otherwise).

    • During a base constructor, virtual calls resolve to the base version because the derived part doesn't exist yet.

Q45.
Explain iterator invalidation. Give an example of an operation that invalidates a std::vector iterator.

Mid

Iterator invalidation is when an operation changes a container such that existing iterators (or pointers/references) no longer point to valid elements; using them afterward is undefined behavior.

  • Why it happens: An operation may reallocate the underlying storage or shift/remove elements, leaving iterators dangling or pointing at the wrong element.

  • std::vector example:

    • push_back() that exceeds capacity() reallocates the buffer, invalidating all iterators, pointers, and references.

    • erase() and insert() invalidate iterators at and after the modification point.

  • Container differences: Node-based containers (std::list, std::map) keep other elements' iterators valid across insert/erase.

  • Safe idiom: erase() returns the next valid iterator: write it = v.erase(it) instead of reusing the old one.

Q46.
Explain the difference between std::map and std::unordered_map. What are the time complexities for their operations, and how do they handle collisions?

Mid

std::map is an ordered, balanced binary search tree giving sorted keys and logarithmic operations; std::unordered_map is a hash table giving average constant-time access but no ordering.

  • std::map:

    • Typically a red-black tree; keys are kept sorted, needing only operator<.

    • Insert, find, erase are O(log n) worst and average.

  • std::unordered_map:

    • Hash table needing a hash function and equality; keys are unordered.

    • Insert, find, erase are O(1) average but O(n) worst case (many collisions / rehash).

  • Collision handling:

    • The standard mandates separate chaining: each bucket holds a list of elements hashing to it.

    • Load factor growth triggers a rehash, which invalidates iterators (but not references to elements).

  • Choosing: Need ordered traversal or range queries: std::map. Need fastest average lookups and order doesn't matter: std::unordered_map.

Q47.
What are the performance tradeoffs between std::vector and std::list? In what scenario is a std::list more efficient?

Mid

A std::vector stores elements contiguously and is the default choice; a std::list is a doubly-linked list that wins only when you do frequent insert/erase in the middle while holding an iterator there, and never need random access.

  • std::vector strengths:

    • Contiguous memory means cache-friendly traversal and O(1) random access via operator[].

    • Low per-element overhead (no node pointers).

  • std::vector weaknesses:

    • Insert/erase in the middle is O(n): elements must shift.

    • Growth may reallocate and invalidate all iterators/pointers.

  • std::list strengths:

    • O(1) insert/erase at a known position, and splice() moves nodes without copying.

    • Stable iterators: inserting/erasing other elements doesn't invalidate them.

  • std::list weaknesses:

    • No random access; finding the position is still O(n).

    • Each node is a separate allocation, so poor cache locality and high memory overhead.

  • When list wins: large/expensive-to-move elements with many mid-sequence insertions/erasures where you already hold the iterator, or heavy use of splice(). In practice std::vector often beats it even at the middle-insert case due to cache effects.

Q48.
What requirements must a class meet to be used as a key in a std::map versus a std::unordered_map?

Mid

A std::map key needs a strict weak ordering (by default operator<); a std::unordered_map key needs a hash function plus an equality comparison.

  • std::map (ordered, balanced BST):

    • Requires a comparator giving strict weak ordering, default std::less<Key> via operator<.

    • No hashing or equality needed: two keys are "equal" when neither is less than the other.

    • Operations are O(log n).

  • std::unordered_map (hash table):

    • Requires a hash functor (default std::hash<Key>) and an equality predicate (default operator==).

    • For custom types you must specialize std::hash or pass a hasher; many built-in/string types already have one.

    • Average O(1) lookup, worst case O(n) on collisions.

  • Shared requirement: the key should effectively be immutable while stored, since mutating the part used for ordering/hashing corrupts the container's invariants.

cpp

struct Point { int x, y; }; // For std::map: ordering bool operator<(const Point& a, const Point& b) { return std::tie(a.x, a.y) < std::tie(b.x, b.y); } // For std::unordered_map: hash + equality struct PointHash { size_t operator()(const Point& p) const { return std::hash<int>{}(p.x) ^ (std::hash<int>{}(p.y) << 1); } }; bool operator==(const Point& a, const Point& b) { return a.x == b.x && a.y == b.y; }

Q49.
How does std::vector manage its internal memory when it reaches capacity, and what is the amortized time complexity of an insertion?

Mid

When a std::vector is full it allocates a new, larger block (typically 1.5x or 2x capacity), moves/copies the existing elements over, and frees the old block; because growth is geometric, push_back is amortized O(1).

  • Reallocation on overflow:

    • If size() == capacity(), it allocates a bigger buffer, transfers elements, and releases the old one.

    • This invalidates all existing iterators, pointers, and references.

  • Geometric growth is the key:

    • Multiplying capacity (not adding a constant) means n insertions trigger O(log n) reallocations touching ~2n elements total.

    • Total work is O(n), so the cost per insertion averages to O(1) amortized, even though individual reallocs are O(n).

  • Move-aware transfer: Elements are moved instead of copied if the type has a noexcept move constructor; otherwise they are copied for the strong exception guarantee.

  • Use reserve() up front when the count is known to avoid repeated reallocations entirely.

Q50.
What is the difference between std::vector::reserve() and std::vector::resize()?

Mid

reserve() changes only capacity (how much memory is allocated) without creating elements; resize() changes size (the number of actual elements), constructing or destroying elements as needed.

  • reserve(n):

    • Ensures capacity is at least n; size() is unchanged and no elements are created.

    • Purpose: pre-allocate to avoid reallocations during later push_back calls.

    • Accessing index n after only reserving is undefined behavior: the elements don't exist yet.

  • resize(n):

    • Makes size() exactly n: appends value-initialized (or given-value) elements if growing, destroys trailing elements if shrinking.

    • After it, indices [0, n) are valid, accessible elements.

  • Both may reallocate and invalidate iterators if capacity must grow.

Q51.
What are the trade-offs of using std::deque over std::vector?

Mid

std::deque gives O(1) push/pop at both ends and avoids invalidating references on end-insertions, but trades away the single contiguous buffer that makes std::vector cache-friendly and C-API compatible.

  • deque advantages:

    • O(1) amortized insertion/removal at both front and back (push_front/push_back); vector has no efficient front insert.

    • Growing doesn't move existing elements, so pushes at the ends don't invalidate references/pointers to existing elements (iterators may still be invalidated).

  • deque disadvantages:

    • Stored as multiple fixed-size chunks, not one contiguous block, so worse cache locality and slower iteration.

    • No data(): you can't hand it to a C API expecting a flat array.

    • Higher memory overhead and a more expensive operator[] (still O(1) but with extra indirection).

  • Rule of thumb: default to std::vector; reach for std::deque when you need fast insertion/removal at both ends (e.g., a queue).

Q52.
What is the difference between emplace_back and push_back in a std::vector?

Mid

push_back takes an already-constructed object and copies or moves it in, while emplace_back forwards its arguments to construct the element in place inside the vector, avoiding a temporary.

  • push_back: Accepts a const T& or T&&; you must supply a T (possibly a temporary that is then moved/copied).

  • emplace_back:

    • Takes the constructor's arguments and builds the object directly in the vector's storage via perfect forwarding, saving a move/copy.

    • Calls explicit constructors that push_back with braces might not, so it can be a bit looser type-wise.

  • Practical note:

    • For an existing object, the two are equivalent in cost (both move).

    • The win is constructing from raw arguments (vec.emplace_back(1, "a") vs vec.push_back(T(1, "a"))).

cpp

std::vector<std::pair<int,std::string>> v; v.push_back(std::make_pair(1, "x")); // build temp, then move v.emplace_back(1, "x"); // construct in place, no temp

Q53.
What are lambda expressions, and how does 'capturing' work (by value vs. by reference)?

Mid

A lambda is an inline anonymous function object; its capture clause [...] decides which surrounding variables it can use and whether it stores a copy (by value) or a reference (by reference).

  • Anatomy: Syntax is [capture](params) -> ret { body }; the compiler generates a closure type with operator().

  • Capture by value [=] or [x]: Copies the variable at capture time; safe to outlive the original. Copies are const unless the lambda is marked mutable.

  • Capture by reference [&] or [&x]: Refers to the original; sees live changes but dangles if the lambda outlives the referenced variable.

  • Other forms: Capture this for member access, init-capture [p = std::move(x)] to move into the closure.

  • Pitfall: returning or storing a [&] lambda beyond the captured scope causes dangling references; prefer by-value for escaping lambdas.

Q54.
Explain the benefits of using std::optional or std::variant over traditional pointers or unions.

Mid

std::optional and std::variant are type-safe, value-semantic alternatives to raw pointers and unions: they track presence/active type for you and manage object lifetimes correctly.

  • std::optional vs a nullable pointer:

    • Expresses "value or nothing" without heap allocation or ownership ambiguity; the object lives inline.

    • A raw pointer conflates absence, ownership, and indirection, and risks dangling/leaks.

  • std::variant vs a raw union:

    • Knows which alternative is active (index()) and accessing the wrong one throws via std::get, instead of silent undefined behavior.

    • Correctly constructs/destructs non-trivial members, which a plain union cannot do automatically.

  • Safer access patterns: Use value_or() for defaults and std::visit to handle every variant case exhaustively.

Q55.
What is std::string_view, and what are the potential pitfalls of using it with temporary strings?

Mid

std::string_view is a non-owning, read-only view (a pointer plus length) over an existing character sequence; it avoids copies, but it does not extend the lifetime of what it points to.

  • What it is: A lightweight handle to characters owned elsewhere (a std::string, literal, or buffer); cheap to copy and pass by value.

  • Why use it: Function parameters accept any string-like source without allocating or copying; substring views via substr are O(1).

  • The temporary pitfall:

    • Viewing a temporary string leaves the view dangling once the temporary is destroyed, causing undefined behavior.

    • Common traps: returning a string_view into a local, or binding one to a function that returns std::string by value.

  • Other caveats: Not guaranteed null-terminated, so don't pass .data() to C APIs expecting a C-string.

cpp

std::string_view sv = std::string("temp"); // dangling: temporary dies std::cout << sv; // undefined behavior std::string s = "safe"; std::string_view ok = s; // fine while s lives

Q56.
What is the difference between std::optional and returning a null pointer?

Mid

Both express "maybe no value," but std::optional<T> is a value-semantic, type-safe wrapper that can hold any type (including non-pointers and values), whereas a null pointer conflates absence with indirection, ownership ambiguity, and the risk of dereferencing null.

  • Expresses intent explicitly: optional says "a value may be absent"; a raw pointer also implies indirection and ownership, muddying meaning.

  • Works for any type, not just pointable objects: You can wrap an int, a struct, etc., without heap allocation; optional stores the value inline.

  • Safer access: value() throws std::bad_optional_access if empty; value_or() supplies a default; has_value() / contextual bool checks presence.

  • No ownership/lifetime questions: A returned pointer raises "do I delete this? is it dangling?"; optional owns its value by copy/move.

  • When a pointer is still right: When you genuinely need to refer to an existing object (not own one), use a pointer or std::optional<std::reference_wrapper<T>>; for polymorphism use a smart pointer.

cpp

std::optional<int> parse(std::string_view s); if (auto n = parse("42")) use(*n); // present int x = parse("bad").value_or(0); // safe default

Q57.
Explain the 'Rule of Three', 'Rule of Five', and 'Rule of Zero'.

Mid

These rules govern when you must define the special member functions that manage resources. The Rule of Three (C++98) and Rule of Five (C++11) say if you define one, you likely need them all; the Rule of Zero says the best design defines none by letting RAII types handle resources for you.

  • Rule of Three:

    • If you define any of the destructor, copy constructor, or copy assignment, you almost certainly need all three (they manage the same resource).

    • Forgetting one leads to leaks, double-frees, or shallow copies sharing a pointer.

  • Rule of Five:

    • C++11 adds the move constructor and move assignment; managing a resource means defining all five for correctness and performance.

    • Declaring a destructor or copy op suppresses implicit move generation, so you must provide moves explicitly to keep move semantics.

  • Rule of Zero:

    • Prefer classes that own no raw resources, so the compiler-generated specials are correct and you write none.

    • Use RAII members (std::unique_ptr, std::vector, std::string) that already implement the rule of five.

  • Bonus: =default and =delete: Use = default to keep an implicit version explicitly, and = delete to forbid copying (e.g. move-only types).

cpp

// Rule of Zero: no special members needed class Widget { std::unique_ptr<Impl> impl_; // handles its own cleanup std::string name_; // destructor, copy/move all correctly generated or deleted };

Q58.
Explain the concept of Resource Acquisition Is Initialization (RAII). Why is it considered a cornerstone of C++ memory safety?

Mid

RAII ties a resource's lifetime to the lifetime of an object: you acquire the resource in a constructor and release it in the destructor, so cleanup happens automatically when the object goes out of scope.

  • The core idea:

    • Constructor acquires (memory, file handle, lock, socket); destructor releases. Ownership lives in the object.

    • Because C++ guarantees destructors run for stack objects when scope exits, cleanup is automatic and deterministic.

  • Why it underpins memory safety:

    • Exception safety: if an exception unwinds the stack, destructors still fire, so no leaks on error paths.

    • No manual delete to forget; ownership and cleanup are paired by design.

  • Standard-library embodiments: Smart pointers (std::unique_ptr, std::shared_ptr), containers (std::vector), and locks (std::lock_guard) are all RAII wrappers.

  • Rule of thumb: never own a raw resource directly; wrap it in an RAII type.

cpp

{ std::lock_guard<std::mutex> g(m); // acquires lock // ... work; may throw } // destructor releases lock automatically

Q59.
What is the difference between constexpr and const?

Mid

const means "this value won't be modified through this name"; constexpr means "this value can be computed at compile time." Every constexpr is implicitly const, but not vice versa.

  • const is about immutability:

    • The value may be set at runtime; it just can't change afterward through that reference.

    • Example: const int n = readInput(); is legal.

  • constexpr is about compile-time evaluation:

    • The initializer must be a constant expression, so it can be used where the compiler needs a constant (array sizes, template args, case labels).

    • Functions can be constexpr too: callable at compile time when given constant arguments, otherwise at runtime.

  • Key distinction: const int a = f(); works even if f() is runtime; constexpr int a = f(); requires f to be evaluable at compile time.

Q60.
What is the difference between static_cast, dynamic_cast, const_cast, and reinterpret_cast?

Mid

They are the four named C++ casts, each expressing a specific, searchable intent instead of the blunt C-style cast.

  • static_cast: Compile-time conversions that are known to be valid: numeric conversions, upcasts, void* back to a type, explicit conversions. No runtime check.

  • dynamic_cast: Safe downcasting in polymorphic class hierarchies: checks at runtime using RTTI. Returns nullptr for pointers or throws std::bad_cast for references on failure.

  • const_cast: Adds or removes const/volatile. Modifying an object that was originally const through it is undefined behavior.

  • reinterpret_cast: Reinterprets the bit pattern (pointer to integer, unrelated pointer types). Most dangerous; implementation-defined and easy to misuse.

  • Why named casts over C-style: They document intent, are grep-able, and restrict what conversions are allowed (a C cast silently tries several, including reinterpret_cast).

Q61.
What is the difference between auto and decltype, and what is decltype(auto)?

Mid

auto deduces a type from an initializer (and strips references/cv-qualifiers like template deduction), while decltype reports the declared type of an expression exactly, including references. decltype(auto) combines them: deduce from the initializer but using decltype rules so reference-ness is preserved.

  • auto strips: By default drops top-level const and references: auto x = ref; copies. You opt back in with auto& or const auto&.

  • decltype preserves: decltype(expr) yields the exact type, references included. Subtle rule: a bare name gives its declared type, but a parenthesized lvalue expression like decltype((x)) yields a reference.

  • decltype(auto) for perfect return types: Mainly used on function returns / forwarding wrappers to return exactly what the wrapped expression yields, keeping references intact (which plain auto would discard).

cpp

int i = 0; int& r = i; auto a = r; // int (reference stripped) decltype(r) b = i; // int& (preserved) decltype(auto) c = r; // int& (deduced with decltype rules)

Q62.
What are the C++ Standard Library algorithms, and why are they preferred over hand-written loops?

Mid

The algorithms in <algorithm> and <numeric> are reusable, generic functions (std::sort, std::find, std::accumulate, std::transform) that operate on iterator ranges. They are preferred because they express intent clearly and are correct, optimized, and composable.

  • Why prefer them over raw loops:

    • Intent is explicit: std::find_if says "search" better than a hand-rolled for loop with a break.

    • Correctness: avoids off-by-one and iterator-invalidation bugs.

    • Performance: implementations are highly tuned and may vectorize; many accept execution policies for parallelism.

  • How they work:

    • They take iterator pairs (or ranges in C++20), decoupling the algorithm from the container.

    • Behavior is customized with predicates/lambdas, not by rewriting the loop.

  • C++20 ranges: std::ranges::sort(v) takes a container directly and supports lazy, composable views.

cpp

// hand loop vs algorithm bool found = false; for (auto& x : v) if (x == target) { found = true; break; } bool found2 = std::find(v.begin(), v.end(), target) != v.end();

Q63.
Explain the difference between an lvalue and an rvalue. Why was the concept of rvalue references introduced in C++11?

Mid

An lvalue names a persistent object you can take the address of; an rvalue is a temporary or pure value with no stable identity. Rvalue references (T&&) were introduced in C++11 so code can detect temporaries and "steal" their resources, enabling move semantics and perfect forwarding.

  • lvalue: Has identity and an address: a named variable, a dereferenced pointer. Can appear on the left of =.

  • rvalue: A temporary that is about to expire: a literal, a function returning by value, the result of a + b.

  • Why rvalue references were added:

    • Before C++11, returning a heavy object copied its buffer even though the source was about to die.

    • T&& lets you overload on temporaries and transfer ownership of their internals (pointers, buffers) instead of deep-copying.

    • Also enables perfect forwarding, preserving value category through generic wrappers.

  • Note: a named rvalue reference variable is itself an lvalue, which is why std::move is needed to pass it on as an rvalue.

Q64.
What are move semantics, and how do they differ from copy semantics?

Mid

Move semantics transfer ownership of a resource (heap memory, file handle) from one object to another instead of duplicating it; copy semantics produce an independent duplicate. Moving leaves the source in a valid but unspecified state and is typically far cheaper.

  • Copy semantics:

    • Deep-copies the underlying resource: both objects own separate data, source unchanged.

    • Invoked via the copy constructor and copy assignment operator.

  • Move semantics:

    • Steals the pointer/handle: a few pointer assignments, no allocation.

    • Invoked via the move constructor and operator=(T&&), which take an rvalue reference (T&&).

  • Triggered by rvalues: Temporaries bind to T&& automatically; force a move on an lvalue with std::move (which is just a cast to rvalue reference).

  • Source state after move: Must be valid but unspecified, so it can still be destroyed or reassigned safely.

Q65.
What is Return Value Optimization (RVO) and Copy Elision?

Mid

Copy elision is a compiler optimization that omits unnecessary copy/move constructions by building the object directly in its final location; RVO is the specific case of eliding the copy/move of a returned local or temporary. Since C++17 some forms are mandatory.

  • RVO (Return Value Optimization):

    • The returned object is constructed directly in the caller's storage, so no copy or move happens.

    • NRVO (named RVO) elides a named local; it is allowed but not guaranteed.

  • Mandatory elision (C++17): Returning a prvalue temporary is guaranteed to be elided: it works even for types with deleted copy and move constructors.

  • Why it matters: Avoids constructor and destructor calls; don't write return std::move(local), as it disables NRVO and forces a move.

cpp

Widget make() { Widget w; // NRVO may elide this return w; // do NOT write return std::move(w); } Widget x = make(); // constructed directly into x

Q66.
What is a deadlock? What are the four necessary conditions for a deadlock to occur, and how can you prevent them in C++?

Mid

A deadlock is a state where two or more threads are each waiting for a resource the other holds, so none can ever proceed. It can occur only when four conditions (the Coffman conditions) hold simultaneously, and breaking any one prevents it.

  • The four necessary conditions:

    1. Mutual exclusion: a resource is held exclusively by one thread.

    2. Hold and wait: a thread holds one resource while waiting for another.

    3. No preemption: a resource can't be forcibly taken; it must be released voluntarily.

    4. Circular wait: a cycle of threads each waiting on the next.

  • Prevention in C++:

    • Break circular wait: always acquire multiple locks in a fixed global order.

    • Lock all at once: std::lock or std::scoped_lock acquire several mutexes deadlock-free.

    • Break hold-and-wait: avoid holding a lock while calling code that takes another.

    • Use try_lock with back-off to avoid waiting indefinitely.

cpp

// Acquire two mutexes safely, no fixed order needed: std::scoped_lock lock(mutexA, mutexB); // C++17, deadlock-free

Q67.
What is the difference between std::lock_guard and std::unique_lock, and when is the flexibility of unique_lock necessary?

Mid

Both are RAII wrappers that lock a mutex on construction and unlock on destruction, but std::lock_guard is minimal and fixed, while std::unique_lock is movable and supports deferred, timed, and manual unlocking. Use unique_lock only when you need that flexibility, since it carries a small overhead.

  • std::lock_guard:

    • Locks at construction, unlocks at scope exit; cannot be unlocked early or moved.

    • Zero-overhead default for a simple critical section.

  • std::unique_lock:

    • Supports lock()/unlock() at will, deferred locking (std::defer_lock), and try_lock_for.

    • Movable, so it can be returned from functions or stored.

  • When the flexibility is necessary:

    • Condition variables: std::condition_variable::wait requires a unique_lock because it must unlock and relock.

    • Manually releasing the lock partway through a scope, or transferring lock ownership.

Q68.
What is std::async and how does it differ from creating a std::thread directly?

Mid

std::async launches a callable and returns a std::future that delivers its result or exception; unlike a raw std::thread, it handles result retrieval, exception propagation, and (with the default policy) the scheduling decision for you.

  • Result and exception handling: future.get() returns the value, and any exception thrown in the task is re-thrown there. A raw std::thread has no return channel and an uncaught exception in it calls std::terminate.

  • Launch policy: std::launch::async forces a new thread; std::launch::deferred runs lazily on the calling thread at get(). The default may pick either, so be explicit when you need a thread.

  • Lifetime and joining: You must join() or detach() a std::thread or it terminates the program. The future from an async task blocks in its destructor until the task finishes.

  • Level of abstraction: std::thread is low-level (you manage everything); std::async is task-based and may reuse a thread pool depending on the implementation.

cpp

auto fut = std::async(std::launch::async, [] { return compute(); }); int result = fut.get(); // waits, returns value or rethrows exception

Q69.
What are 'inline' functions, and does the compiler always respect the inline keyword?

Mid

An inline function is one whose definition is visible in each translation unit and may have its call replaced by its body to avoid call overhead. The keyword is only a hint for that optimization: the compiler is free to ignore it and may also inline functions you never marked.

  • The two meanings of inline:

    • Optimization hint: substitute the body at the call site, trading code size for fewer call/return and stack-frame costs.

    • Linkage rule (the guaranteed part): it relaxes the one-definition rule, allowing identical definitions in multiple translation units, which is why inline functions live in headers.

  • The compiler decides:

    • It may inline despite no keyword, or refuse to inline large/recursive functions even when marked.

    • Taking the function's address or calling it via a pointer forces an out-of-line copy.

  • Practical notes:

    • Member functions defined inside a class body are implicitly inline.

    • Over-inlining bloats code and can hurt instruction-cache performance, so favor trusting the optimizer (and link-time optimization) over manual hints.

Q70.
What are function pointers and what are their typical use cases in systems-level C++?

Mid

A function pointer is a variable that stores the address of a function, letting you call or pass behavior at runtime. In systems-level C++ they enable callbacks, plug-in dispatch tables, and interop with C APIs.

  • Syntax and basics:

    • Declared as ret(*name)(args); assign a function name (which decays to its address) and call via name(...).

    • A plain function pointer carries no state, unlike a functor or capturing lambda.

  • Typical use cases:

    • Callbacks: passing a handler to C APIs (qsort, signal, OS/driver callbacks).

    • Dispatch / jump tables: an array of function pointers indexed by an opcode or state, used in interpreters and state machines.

    • Pluggable strategy: swapping implementations at runtime without inheritance.

    • C interop: an ABI-stable way to register handlers since C has no templates or lambdas.

  • Modern note: In pure C++ prefer std::function or templates/lambdas when you need captured state, but only a non-capturing lambda converts to a raw function pointer for C callbacks.

cpp

int add(int a, int b) { return a + b; } int (*op)(int, int) = &add; // or = add int r = op(2, 3); // calls add -> 5

Q71.
What is a functor (function object) and how does it differ from a regular function?

Mid

A functor is an object of a class that defines operator(), so it can be called like a function while also holding state. Unlike a plain function, each functor instance can carry its own data and its call can be inlined by the compiler.

  • What makes it a functor: Any class overloading operator(); instances are invoked with f(args) syntax.

  • Differences from a regular function:

    • State: member variables let it remember data across calls (e.g. a running total, a configured threshold), which a stateless function can't.

    • Each functor is a distinct type, so templates can inline its call, often outperforming a function pointer.

    • Can have multiple overloaded operator() and other members.

  • Relationship to lambdas:

    • A lambda is syntactic sugar for a compiler-generated functor; its captures become member variables.

    • Heavily used by STL algorithms as comparators and predicates (std::sort, std::for_each).

cpp

struct GreaterThan { int threshold; bool operator()(int x) const { return x > threshold; } }; GreaterThan gt{10}; bool b = gt(15); // true; carries state (threshold) std::count_if(v.begin(), v.end(), GreaterThan{10});

Q72.
What is std::function and what overhead does it introduce compared to a lambda or function pointer?

Mid

std::function is a polymorphic, type-erased wrapper that can hold any callable (lambda, function pointer, functor, bound member) with a matching signature. That flexibility costs more than a raw lambda or function pointer: an indirect call, possible heap allocation, and lost inlining.

  • What it is:

    • A uniform handle over heterogeneous callables sharing one signature, e.g. std::function<int(int)>.

    • Uses type erasure: the concrete callable type is hidden behind a virtual-like dispatch interface.

  • Overhead it introduces:

    • Indirect call through type erasure, so the compiler usually cannot inline the target.

    • Possible heap allocation: large callables (big captures) spill to the heap; small ones fit in a small-buffer optimization.

    • Larger object size and copy cost compared to a pointer.

  • Contrast with the alternatives:

    • A lambda has a unique unnamed type and is typically inlined: zero overhead, but you can't store heterogeneous lambdas in one variable.

    • A function pointer is tiny and cheap but holds no state (no captures).

    • Templates (or auto / a template parameter) keep the concrete type and avoid erasure entirely.

  • Rule of thumb: use std::function when you need to store or pass callables of differing types behind one stable interface; prefer templates/lambdas on hot paths.

Q73.
What are the pros and cons of using Exceptions vs. Error Codes?

Mid

Exceptions separate the error path from the normal path and cannot be silently ignored, while error codes are explicit, cheap, and predictable but easy to forget. The choice hinges on whether errors are truly exceptional and on your performance and code-clarity constraints.

  • Exceptions: pros:

    • Cannot be ignored: an unhandled throw propagates rather than being silently dropped.

    • Keep the happy path clean: no return-value checking after every call.

    • Carry rich context (a type plus a payload) and work where return values can't, e.g. constructors and operators.

  • Exceptions: cons:

    • Throwing is expensive (stack unwinding); banned or avoided in many real-time/embedded codebases.

    • Control flow is non-local and harder to follow; demands exception-safe, RAII-based code.

  • Error codes: pros:

    • Cheap and deterministic, with no hidden control flow.

    • Explicit at every call site; easy for static analysis.

  • Error codes: cons:

    • Easy to ignore unless forced (e.g. [[nodiscard]]).

    • Clutter the normal path with checks and propagate manually up the call chain.

  • Middle ground: std::expected / std::optional give value-or-error semantics without throwing.

  • Guideline: exceptions for genuinely exceptional, unrecoverable-here failures; codes/expected for expected, routine outcomes.

Q74.
Why is it generally considered a bad practice to throw an exception from a destructor? What happens if an exception is thrown during stack unwinding?

Mid

Throwing from a destructor is dangerous because destructors run during stack unwinding, and if a second exception escapes while another is already propagating, C++ has no way to choose between them and calls std::terminate(). Destructors are also implicitly noexcept in modern C++, so a throw aborts immediately.

  • The core problem: two exceptions at once:

    • When an exception unwinds the stack, each local object's destructor runs. If one of those destructors throws, you now have two active exceptions.

    • The standard cannot reconcile them, so std::terminate() is called: instant program death, no further cleanup.

  • Destructors are implicitly noexcept: Since C++11, destructors default to noexcept; an escaping exception triggers std::terminate() even outside unwinding.

  • What to do instead:

    • Handle and swallow errors inside the destructor (log them) rather than letting them escape.

    • Offer a separate close()/commit() method that can throw, so failure can be reported during normal flow.

    • You can query std::uncaught_exceptions() to detect active unwinding, but designing not to throw is cleaner.

Q75.
What happens if an exception is thrown inside a constructor or a destructor?

Mid

A throw from a constructor is normal and safe: the object never finishes construction, so any already-constructed members and base classes are destroyed in reverse order. A throw from a destructor is the dangerous case, risking std::terminate().

  • Exception in a constructor:

    • The object's lifetime never begins, so its own destructor is NOT called.

    • Fully-constructed members and base subobjects ARE destroyed in reverse order, so RAII members clean themselves up.

    • Key consequence: a resource acquired raw in the constructor body (not wrapped in RAII) leaks because there's no destructor to release it. Wrap members so each owns its resource.

  • Exception in a destructor:

    • Destructors are implicitly noexcept, so an escaping exception calls std::terminate().

    • If it happens during stack unwinding from another exception, two live exceptions also force std::terminate(). Contain errors inside the destructor.

cpp

struct Widget { std::unique_ptr<Resource> r; // RAII member Widget() : r(std::make_unique<Resource>()) { throw std::runtime_error("fail"); // r is already constructed -> its destructor runs, no leak // Widget::~Widget() is NOT called (object never completed) } };

Q76.
What is the purpose of the volatile keyword in C++? Does it provide any thread-safety guarantees?

Mid

The volatile keyword tells the compiler that a variable's value may change at any time outside the program's control, so it must not optimize away reads/writes (no caching in registers, no reordering of accesses to it). It is about preventing optimization, not about concurrency, and it provides no thread-safety guarantees.

  • Legitimate uses:

    • Memory-mapped hardware registers and I/O where each access has a side effect.

    • Variables modified by a signal handler (paired with sig_atomic_t).

  • What it does NOT do:

    • It guarantees no atomicity: a volatile read-modify-write is still non-atomic.

    • It imposes no memory ordering/fences across threads, so it can't safely synchronize data between threads.

  • Use std::atomic for concurrency: Atomics provide atomicity plus a defined memory model (acquire/release ordering), which is what thread communication actually needs.

  • Note: Java/C# volatile implies memory ordering; C++ volatile does not. Conflating them is a common interview trap.

Q77.
Why are templates usually implemented in header files rather than source files?

Mid

Because a template is not code, it's a blueprint: the compiler only generates a concrete function/class when it sees the template definition together with the specific types used to instantiate it. So the full definition must be visible in every translation unit that uses it, and the simplest way to achieve that is to put it in a header.

  • The root cause: Instantiation happens at the point of use; if the definition lives in a separate .cpp, other translation units see only the declaration and can't generate code, causing linker errors.

  • The ODR angle: Templates are exempt from the usual one-definition rule across TUs; identical definitions in multiple units are fine and the linker merges duplicate instantiations.

  • Alternatives:

    • Explicit instantiation: define in a .cpp and write template class Foo<int>; for the few types you support.

    • C++20 modules ease this by exporting templates without textual header inclusion.

Q78.
Explain the concept of Type Traits. How does the compiler use them to make decisions at compile time?

Mid

Type traits are small template structs that expose compile-time information about a type (or transform it), letting generic code query properties like "is this integral?" or "remove the reference" and make decisions before runtime.

  • Two flavors:

    • Predicate traits expose a ::value (e.g. std::is_pointer<T>::value); the _v suffix is the variable-template shortcut.

    • Transformation traits expose a ::type (e.g. std::remove_const<T>::type); the _t suffix is the alias shortcut.

  • How the compiler uses them:

    • They are implemented via template specialization: the primary template gives a default answer and specializations override it for specific types, so the compiler picks the matching one during instantiation.

    • Their constant results feed if constexpr, static_assert, std::enable_if, and concepts to select overloads, prune branches, or reject ill-typed instantiations.

  • Effect: dispatch happens entirely at compile time, so there is no runtime branch or cost.

cpp

template<typename T> void process(T v) { if constexpr (std::is_integral_v<T>) fast_int_path(v); // only compiled for integral T else generic_path(v); }

Q79.
What is the difference between internal and external linkage (the static and extern keywords)?

Mid

Linkage determines whether a name can be referred to from other translation units: a name with external linkage is visible to the whole program and resolvable by the linker, while a name with internal linkage is private to its own translation unit.

  • External linkage:

    • Default for non-const globals and free functions; one definition is shared across the program.

    • extern declares (does not define) such a name so multiple TUs can reference the single definition.

  • Internal linkage:

    • static at namespace scope (or an unnamed namespace) gives each TU its own private copy, invisible to others.

    • const / constexpr globals have internal linkage by default in C++.

    • Prevents name clashes and ODR conflicts at link time.

  • Modern guidance: prefer unnamed namespaces over file-scope static for internal linkage, and inline variables (C++17) for header-defined shared globals.

Q80.
What is 'Name Mangling', and why is extern "C" necessary when linking with C code?

Mid

Name mangling is how a C++ compiler encodes a function's namespace, class, and parameter types into its linker symbol so that overloading works; extern "C" turns mangling off so the symbol uses the plain C name, which is required to link against C code.

  • Why C++ mangles names:

    • foo(int) and foo(double) must produce distinct symbols, so the type info is baked into the mangled name.

    • The exact scheme is implementation-defined and varies between compilers.

  • Why C needs extern "C":

    • C does not overload, so it emits unmangled symbols like foo.

    • Without extern "C", the C++ caller looks for a mangled symbol the C object file never defines, causing unresolved-symbol link errors.

  • Usage: wrap C declarations in a header guarded for both languages.

cpp

#ifdef __cplusplus extern "C" { #endif int c_add(int a, int b); // unmangled symbol #ifdef __cplusplus } #endif

Q81.
What is the One Definition Rule (ODR), and what happens if it is violated?

Mid

The One Definition Rule states that every entity must have exactly one definition across the whole program (though it may be declared many times), and certain entities like inline functions, templates, and classes may be defined in multiple translation units only if all definitions are token-for-token identical.

  • What ODR requires:

    • Exactly one definition per non-inline function and per used variable in the entire program.

    • Classes, templates, inline functions/variables, and enums may appear in multiple TUs but every copy must be identical, which is why they go in headers.

  • What happens on violation:

    • Two definitions of the same non-inline symbol cause a multiple-definition link error.

    • Inconsistent definitions (e.g. a class laid out differently in two TUs) are usually undefined behavior with no diagnostic required: the linker silently picks one, causing crashes or subtle corruption.

  • How to stay safe: Declare in headers, define in one .cpp; mark header-defined functions/variables inline; keep header contents consistent across all includers.

Q82.
What is Name Mangling and why is it necessary for C++ to support function overloading?

Mid

Name mangling is the compiler's technique of encoding a function's name together with its parameter types (and namespace, class, etc.) into a unique symbol name. It is necessary because the linker works on plain symbol names, and overloaded functions share the same source name but must map to distinct symbols.

  • What it encodes:

    • The function name plus parameter types, namespaces, class scope, and const/ref qualifiers are folded into one decorated symbol.

    • Example: void f(int) and void f(double) become different mangled symbols.

  • Why overloading needs it:

    • The linker resolves calls by symbol name only; without mangling, two overloads would collide as duplicate symbols.

    • Mangling guarantees each overload gets a unique linker symbol so the right one is resolved.

  • Interop with C:

    • C does not mangle names; use extern "C" to suppress mangling so C++ and C code can link together.

    • Note: return type is generally NOT part of the mangled name, which is why you can't overload on return type alone.

Q83.
What is the difference between a forward declaration and including a header? When can you forward declare?

Mid

A forward declaration just names a type so the compiler knows it exists, while including a header brings in its full definition. Forward declaring reduces compile-time coupling and dependencies, but you can only do it when the incomplete type is enough.

  • Forward declaration:

    • e.g. class Widget; creates an incomplete type: you know the name but not its layout.

    • Speeds compilation and breaks cyclic include dependencies.

  • When forward declaration is enough:

    • Pointers or references to the type (Widget*, Widget&).

    • Function declarations that take or return the type by value (in declarations, not calls).

  • When you must include the header:

    • Accessing members, calling methods, or knowing the size (declaring a member by value, inheriting, sizeof, instantiating).

    • Anything that requires a complete type.

Q84.
What happens during the different stages of compilation and linking in C++ (preprocessing, compilation, linking)?

Mid

Building a C++ program moves source through preprocessing, compilation, and linking: the preprocessor expands text, the compiler turns each translation unit into object code, and the linker stitches objects and libraries into a final executable.

  • Preprocessing:

    • Handles directives: #include pastes headers in, #define expands macros, and #ifdef strips conditional code.

    • Output is a single expanded translation unit of pure C++.

  • Compilation:

    • Parses and type-checks the translation unit, then generates an object file (.o/.obj) of machine code.

    • Unresolved external symbols are left as placeholders for the linker.

  • Linking:

    • Combines object files and libraries, resolves symbols across them, and lays out the final binary.

    • Errors here (undefined reference, duplicate symbol) reflect missing or repeated definitions, not syntax.

Q85.
How does cache locality affect the performance of C++ code?

Mid

Cache locality determines how often the CPU finds data in fast caches versus paying a costly trip to main memory. Code that accesses memory in predictable, contiguous patterns runs dramatically faster because it maximizes cache hits, even when the algorithmic complexity is identical.

  • Two kinds of locality:

    • Spatial: accessing nearby addresses (a contiguous array) means data already in the loaded cache line is reused.

    • Temporal: reusing the same data soon keeps it hot in cache.

  • Why it dominates performance:

    • A cache miss to RAM can cost ~100x an L1 hit, so memory layout often matters more than instruction count.

    • Caches load whole lines (typically 64 bytes), so sequential access amortizes each fetch.

  • Practical consequences:

    • Prefer std::vector (contiguous) over std::list (scattered nodes, pointer chasing).

    • Structure-of-arrays can beat array-of-structs when you touch only some fields.

    • Iterate row-major arrays in row order to match memory layout.

Q86.
How does memory alignment affect CPU cache performance? What is structure padding?

Mid

Memory alignment means placing data at addresses that are multiples of its natural size; aligned data is fetched in fewer cache-line accesses, while misaligned or padded data wastes cache space and bandwidth. Structure padding is the compiler inserting unused bytes between members to satisfy each member's alignment requirement.

  • Why alignment matters for the CPU:

    • Memory is read in fixed cache lines (typically 64 bytes); aligned objects fit cleanly and never straddle two lines.

    • A misaligned access may span two cache lines, forcing two loads, and on some architectures it faults or is much slower.

  • What structure padding is:

    • Each member must sit at an offset that is a multiple of its alignment, so the compiler inserts filler bytes.

    • The struct's total size is rounded up to a multiple of its largest member's alignment so arrays stay aligned.

  • Practical impact:

    • Reordering members largest-to-smallest minimizes padding and shrinks the footprint, fitting more objects per cache line.

    • Smaller, denser structs improve cache hit rate and reduce memory traffic in hot loops.

    • Use alignof / alignas to inspect or force alignment (e.g. align hot data to a cache line to avoid false sharing).

cpp

struct Bad { // sizeof == 24 (lots of padding) char a; // 1 byte + 7 padding double b; // 8 bytes char c; // 1 byte + 7 padding }; struct Good { // sizeof == 16 double b; char a; char c; };

Q87.
What is 'Undefined Behavior' in C++, and why is it a significant concern?

Mid

Undefined behavior (UB) is any operation for which the C++ standard imposes no requirements: once a program executes UB, the entire program is invalid and the compiler may do literally anything, from crashing to silently producing wrong results. It's a major concern because UB can appear to work, then break under optimization, a new compiler, or different inputs.

  • What it means:

    • The standard makes no guarantees: behavior may vary by compiler, optimization level, or run.

    • Distinct from unspecified behavior (one of several valid outcomes) and implementation-defined behavior (documented per platform).

  • Why it's dangerous:

    • Optimizers assume UB never happens, so they may delete checks or reorder code, producing bizarre results.

    • Bugs are nondeterministic and may stay hidden until a release build or a different machine.

  • Common sources: Out-of-bounds access, dereferencing null/dangling pointers, signed integer overflow, data races, use-after-free, reading uninitialized values.

  • Mitigation: Use sanitizers (-fsanitize=address,undefined), warnings, and tools like Valgrind to catch UB early.

Q88.
Explain the difference between big-endian and little-endian byte ordering. Why does this matter when writing portable C++ code?

Mid

Endianness is the order in which a multi-byte value's bytes are stored in memory: big-endian stores the most significant byte first (lowest address), little-endian stores the least significant byte first. It matters for portability whenever raw bytes cross a boundary (files, network, different hardware), because the same bytes can mean different numbers on different machines.

  • The two orderings:

    • Big-endian: 0x12345678 stored as bytes 12 34 56 78 (network byte order, some older RISC).

    • Little-endian: stored as 78 56 34 12 (x86, ARM in practice).

  • Why it breaks portability:

    • Reinterpreting an integer as raw bytes and sending them to another machine gives a different value if endianness differs.

    • Affects binary file formats, network protocols, and reinterpret_cast / memcpy over byte buffers.

  • How to write portable code:

    • Define a fixed serialization order and convert with htonl/ntohl or C++20 std::endian / std::byteswap.

    • Serialize byte-by-byte with explicit shifts rather than dumping struct memory.

cpp

// Portable big-endian serialization, independent of host endianness void write_be32(uint8_t* p, uint32_t v) { p[0] = v >> 24; p[1] = v >> 16; p[2] = v >> 8; p[3] = v; }

Q89.
What is undefined behavior (UB), and can you give an example of it in C++?

Mid

Undefined behavior (UB) is code whose result the C++ standard deliberately leaves completely unspecified: a program that executes UB has no defined meaning at all, and the compiler is free to do anything (crash, wrong output, or seemingly work). A classic example is reading or writing past the end of an array.

  • Definition: The standard imposes no requirements; compilers optimize assuming UB cannot occur.

  • Concrete examples:

    • Out-of-bounds array indexing.

    • Signed integer overflow (INT_MAX + 1).

    • Dereferencing a null or dangling pointer, use-after-free, double free.

    • Reading an uninitialized variable, or a data race between threads.

  • Why it bites: It may appear to work in debug builds then fail in optimized builds, since optimizers exploit the assumption.

cpp

int a[3] = {1, 2, 3}; int x = a[5]; // UB: out-of-bounds read int v = INT_MAX; int y = v + 1; // UB: signed overflow

Q90.
What is undefined behavior? Why does the C++ standard allow it?

Mid

Undefined behavior is any construct the C++ standard explicitly leaves with no defined semantics, so the implementation may do anything. The standard allows it mainly for performance and portability: it lets compilers assume programs are well-formed and generate fast code without inserting runtime checks for every operation.

  • What UB is: A program triggering UB is invalid; the standard guarantees nothing about its execution.

  • Why the standard permits it:

    • Performance: avoids mandatory bounds checks, overflow checks, and null checks that would slow every program.

    • Optimization freedom: the compiler can assume UB never happens and aggressively transform code (reorder, eliminate dead checks).

    • Hardware diversity: leaving edge cases undefined lets each platform use its most efficient native behavior.

    • Simplicity: the standard avoids legislating every corner case across all possible architectures.

  • The trade-off: It puts the burden of correctness on the programmer: "don't pay for what you don't use" comes at the cost of safety.

Q91.
How is std::unique_ptr implemented to ensure only one owner exists? How does it differ from std::shared_ptr in terms of memory overhead?

Senior

std::unique_ptr enforces single ownership by deleting its copy operations and only allowing moves, so at most one unique_ptr ever holds a given resource. It is a zero-overhead wrapper, whereas std::shared_ptr carries an extra control block for reference counting.

  • Single ownership mechanism:

    • Copy constructor and copy assignment are = delete; only the move constructor/assignment transfer the pointer and null out the source.

    • Its destructor calls the deleter on the held pointer, guaranteeing one cleanup.

  • Memory overhead:

    • With the default deleter it is the size of a raw pointer (the deleter is stateless and stored via empty-base optimization).

    • No control block, no atomic counters: truly zero runtime cost over a raw pointer.

  • Contrast with shared_ptr:

    • shared_ptr is typically two pointers wide (object + control block) and the control block holds atomic strong/weak counts.

    • Copying is allowed and bumps the counter, so shared_ptr pays for both space and atomic increments/decrements.

Q92.
How do you think about memory ownership and resource management on a fast-moving team, and when is a raw pointer still acceptable?

Senior

Make ownership explicit and visible in the type system: prefer RAII and smart pointers so lifetimes are obvious to teammates moving fast, and reserve raw pointers for non-owning observation where the lifetime is clearly guaranteed elsewhere.

  • Default to RAII: Tie every resource (memory, files, locks, sockets) to an object whose destructor releases it, so cleanup is automatic and exception-safe.

  • Encode ownership in the type:

    • std::unique_ptr for single ownership (the common default), std::shared_ptr only when ownership is genuinely shared.

    • std::weak_ptr breaks reference cycles and expresses 'observe but don't keep alive'.

  • Raw pointers are fine as non-owning handles:

    • A function parameter that observes but does not store or free the object (passing .get() or a reference is even better).

    • Optional, rebindable references where the pointee outlives the pointer by construction.

    • Never use new/delete on a raw pointer that an owner-type could manage instead.

  • Team hygiene: A clear rule (owners hold smart pointers, APIs take raw pointers/references for borrowing) lets reviewers spot leaks and dangling at a glance.

Q93.
Why might you avoid using Multiple Inheritance in a large-scale project?

Senior

Multiple inheritance lets a class derive from several bases, but it introduces ambiguity, fragile coupling, and the diamond problem, so large codebases often prefer single inheritance plus composition or interface-only inheritance.

  • The diamond problem: If two bases share a common ancestor, the derived class gets two copies of it unless you use virtual inheritance, which adds complexity and overhead.

  • Name and member ambiguity: Two bases with the same member name force explicit qualification and make calls harder to reason about.

  • Tight coupling and fragility: The class now depends on the internals of multiple hierarchies, so changes ripple widely.

  • Safer alternatives: Inherit from multiple pure-interface (abstract) classes, which avoids data-layout conflicts, and use composition for implementation reuse.

Q94.
Explain the Small String Optimization (SSO) used by many STL implementations.

Senior

Small String Optimization stores short strings directly inside the std::string object's own stack buffer instead of on the heap, avoiding a dynamic allocation for common small strings.

  • How it works:

    • The string object reserves a small inline buffer (often ~15 chars on 64-bit) inside its own storage.

    • If the content fits, it lives inline; if it exceeds the threshold, the string allocates on the heap and the pointer/size/capacity layout is used instead (often a union).

  • Why it matters:

    • Eliminates heap allocation/free for short strings, which dominate real workloads (keys, tokens, identifiers).

    • Better cache locality since the data sits with the object.

  • Consequences to know:

    • It makes sizeof(std::string) larger than a bare pointer (typically 24-32 bytes).

    • The exact buffer size and threshold are implementation-defined (libstdc++, libc++, MSVC differ).

    • Moving a SSO string copies the buffer rather than just stealing a pointer, so move isn't always trivially cheap for short strings.

Q95.
What are C++20 Concepts, and how do they improve template programming?

Senior

Concepts are named, compile-time predicates that constrain template parameters, so templates state what types they require instead of failing deep inside instantiation.

  • They constrain templates: A concept expresses requirements (operations, return types, members) a type must satisfy.

  • Clearer error messages: Violations are reported at the call site ("type does not satisfy concept") rather than as pages of template-instantiation noise.

  • Better overloading: Constraints participate in overload resolution and partial ordering, a cleaner replacement for std::enable_if / SFINAE.

  • Self-documenting interfaces: The signature itself shows intent; the standard library ships ready-made ones like std::integral and std::ranges::range.

cpp

template <typename T> concept Number = std::integral<T> || std::floating_point<T>; template <Number T> T add(T a, T b) { return a + b; }

Q96.
What is the purpose of std::expected (C++23) and how does it change error handling compared to exceptions or error codes?

Senior

std::expected<T, E> holds either a success value of type T or an error of type E, making failure an explicit part of the return type without throwing or relying on out-of-band error codes.

  • Errors are in the type system: The signature shows it can fail, and you check with has_value(), reading value() or error().

  • Versus exceptions: No stack unwinding or hidden control flow; cheaper for expected/recoverable failures and usable where exceptions are disabled.

  • Versus error codes: The value and error share one return; you can't accidentally read the value while ignoring the error.

  • Composable: Monadic helpers like and_then, transform, and or_else chain operations without manual branching.

cpp

std::expected<int, std::string> parse(std::string_view s); auto r = parse("42"); if (r) use(*r); else log(r.error());

Q97.
What are Coroutines in C++20, and what are their primary use cases?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q98.
Explain how C++20 Coroutines work at a high level (Promises, Awaitables).

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q99.
What is 'deducing this' in C++23, and how does it simplify the CRTP pattern?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q100.
What are coroutines in C++20, and how do they differ from standard functions in terms of stack management?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q101.
Walk me through a recent use of a modern C++ feature like Concepts, Ranges, or Coroutines and explain why you chose it over the traditional alternative.

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q102.
How do C++20 Concepts improve template error messages compared to SFINAE?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q103.
What are C++20 Modules, and how do they fundamentally change the compilation model compared to header files?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q104.
What are C++20 Ranges, and how do they differ from traditional iterator-based algorithms?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q105.
Explain the difference between constexpr, consteval, and constinit. When would you use one over the others?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q106.
What is the difference between std::move and std::forward? When would you use move semantics over traditional copying?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q107.
Explain perfect forwarding and why std::forward is necessary in template wrappers.

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q108.
What is the 'noexcept' specifier and how does it affect performance and move semantics?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q109.
Explain the difference between std::atomic and using a std::mutex. When is an atomic operation not enough to ensure thread safety?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q110.
What is the difference between a condition variable and busy-waiting? How does std::condition_variable work?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q111.
What is the performance overhead of a virtual function call?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q112.
What are the different categories of exception safety guarantees (no-throw, strong, basic)?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q113.
Explain the C++ memory model and the difference between 'sequentially consistent' and 'relaxed' memory ordering.

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q114.
What is the C++ Memory Model, and why is it important for multi-threaded applications?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q115.
What is a data race, and how does the C++ standard define its consequences?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q116.
What is false sharing, and how can you use alignas to prevent it in a multithreaded environment?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q117.
What is a lock-free data structure, and what are the risks of implementing one such as the ABA problem?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q118.
What is a Data Race versus a Race Condition? Can you have one without the other?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q119.
What is template specialization (full vs. partial)?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q120.
Explain SFINAE (Substitution Failure Is Not An Error).

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q121.
What is the Curiously Recurring Template Pattern (CRTP) and what is it used for?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q122.
What is Template Metaprogramming (TMP), and when would you use it?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q123.
What is template bloat, and how can you minimize it?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q124.
What is variadic template, and how do you process a parameter pack?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q125.
What is the 'Static Initialization Order Fiasco' and how can it be avoided?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q126.
What is argument-dependent lookup (ADL) in C++?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q127.
What is branch prediction, and how can writing branchless code improve C++ performance?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.

Q128.
Explain the difference between CUDA cores and Tensor cores. How do you optimize C++ code for parallel execution on a GPU?

Senior
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem.