Skip to content

Latest commit

 

History

History
727 lines (586 loc) · 28 KB

File metadata and controls

727 lines (586 loc) · 28 KB

C++

Table of Contents generated with DocToc

Questions

1. General

1.1 How does static affect a variable?

  • static global variables
    • internal linkage: visible in current translation unit
    • prevents name conflicts with other files
  • static local variables
    • persists b/w function calls
    • initialized once (1st call)

1.2 How does const affect a variable?

const makes a variables read-only after initialization

const int v = 1;    // const var: can't modify v
const int& r = v;   // const ref: can't modify through r
const int* p1 = &v; // ptr to const (data is const): can't modify *p, can change p
int const* p2 = &v; // same
int* const p3 = &v; // const ptr (ptr is const): can't change p, can modify *p
const int* const p4 = &v; // const ptr to const: nothing is modifiable
  • must be initialized at declaration
  • compiler may optimize (in read-only memory)
  • for global const: internal linkage by default (unlike C)
  • enables compile-time optimizations

1.3 How does extern affect a variable?

  • variable declaration (no definition)
// abc.cpp
int var = 10;   // definition

// xyz.cpp
extern int var; // declaration
  • prevent const internal linkage
extern const int var = 10;  // external linkage
  • extern "C" linkage: disable name mangling: extern "C" void f();
  • template explicit instaniation declaration
extern template class std::vector<int>;  // don't instantiate here

1.4 What is explicit and implicit type casting in C++

  • Implicit (automatic): double d = i;, Derived* -> Base*, single-arg ctor
  • Explicit (C++ casts):
Cast Purpose Example
static_cast<T> Compile-time checked conversions; downcast only if you already know the type (no run-time check) static_cast<int>(d)
dynamic_cast<T> Checked downcast (run-time, needs RTTI) dynamic_cast<D*>(bp)
const_cast<T> Add/remove const/volatile const_cast<int&>(cr)
reinterpret_cast<T> Bit reinterpretation (dangerous!) reinterpret_cast<char*>(p)

static_cast vs dynamic_cast -- downcast Base* -> Derived*:

Base* b = get();
auto* d1 = static_cast<Derived*>(b);   // unsafe: UB if b isn't a Derived
auto* d2 = dynamic_cast<Derived*>(b);  // safe: nullptr if it isn't
  • static_cast: free, you guarantee the type
  • dynamic_cast: runtime check, polymorphic types only (>= 1 virtual fn); ptr -> nullptr on failure, ref -> throws std::bad_cast

const_cast -- changes only cv-qualifiers, never the type:

int i = 1;
const int& cr = i;
const_cast<int&>(cr) = 2;         // OK: i wasn't really const

const int c = 1;
const_cast<int&>(c) = 2;          // UB! object is truly const
  • adding const is always safe (implicit anyway)
  • removing it is only safe if the object isn't const -- mainly for legacy C APIs

1.5 What types of overloading are there?

  • function: same name, different params types/count
  • operator: custom behavior
  • template: generic & specialized

Resolution rules:

  • exact match
  • promotion (int -> long)
  • standard conversion (int -> double)
  • user-defined conversion
  • elipsis (...)

Restrictions:

  • return type alone
  • const/volatile on value params

2. Classes

2.1 What are the different types of ctors?

  • default: A(), no parameters!
  • parameterized: A(int x, int y)
  • copy: A(const A& other), copies another object of same type
  • move (C++11): A(A&& other) noexcept, transfers resources
    • no const
    • don't throw while moving!
  • delegating (C++11): A() : A(0), call another ctor
  • converting: A(int x), single arg, enables implicit conversion
  • explicit: explicit A(int x), prevents implicit conversion

2.2 What are the differences b/w private/protected/public?

Specifier Class Derived Class Outside
private Y N N
protected Y Y N
public Y Y Y

2.3 What is the difference b/w struct & class?

Aspect struct class
Default access public private
Default inheritance public private

2.4 What is a union?

Stores different types in the same memory location (ME).

union Data {
    int i;
    float f;
};

C++17 alternative: std::variant (type-safe union)

2.5 What methods are standard for a class?

Special member functions generated by the compiler:

  • default ctor: T()
  • dtor: ~T()
  • copy ctor: T(const T&)
  • copy assign. op: T& operator=(const T&)
  • move ctor: T(T&&) (C++11)
  • move assign. op: T& operator=(T&&) (C++11)

Rule of Zero/Three/Five:

  • if you define none, the compiler generates all
  • if you define dtor, copy ctor, or copy assign, define all three
  • C++11: if you define any, consider defining all five

2.6 What's an abstract class?

Abstract class

  • has at least one pure virtual function
  • cannot be instantiated

Purpose:

  • define interfaces
  • force derived classes to implement specific methods
  • enable polymophism

2.7 What is an enum?

An enumeration defines a set of named integer constants

  • C-style enum
enum Color { C, M, Y, K }; // C=0, M=1, Y=2, K=3
Color c = C;
int i = c; // implicit conversion
  • enum class (C++11)
enum class Color { C, M, Y, K };
Color c = Color::C;
//int i = c;                 // ERROR: no implicit conversion
int i = static_cast<int>(c); // OK
  • with underlying type: enum class S : size_t { OK=0, E=1 }

2.8 What is mutable used for?

mutable data members can be modified by const member functions

Use cases:

  • caching computed values
  • logging/debugging counters
  • mutexes (for thread-safe const methods)

2.9 What are const methods used for?

Only const member functions can be called by const objects.

3. Memory

3.1 Where can a variable be stored?

Location Description Lifetime
Stack Local non-static variables, function parameters Function scope
Heap Dynamic allocation (new, malloc) Until delete/free
Data segment Global/static initialized variables Program lifetime
BSS segment Global/static uninitialized variables (zero) Program lifetime
Registers Compiler optimization, register hint Temporary
Text segment String literals (read-only) Program lifetime

3.2 What is a pointer?

A variable that stores a memory address.

op name example
& address-of &var
* dereference *ptr
= assignment ptr = &x
+/ -/ ++/ -- arithmetic ptr+n, ptr++
==/ != / < / > / <= / >= comparison *ptr == x
[] array subscript ptr[i] == *(ptr+i)
-> member access ptr->member
static_cast, reinterpret_cast casting static_cast<int*>

Types:

  • int*: ptr to int
  • int**: ptr to ptr to int
  • void*: generic ptr
  • nullptr: null ptr (C++11)

3.3 What is the size of a ptr?

It's arch-dependent:

arch ptr size
32-bit 4 bytes
64-bit 8 bytes

All object ptrs have same size on the same platform:

sizeof(int*) == sizeof(double*) == sizeof(void*)
// check
std::cout << sizeof(void*);

But ptr-to-member is NOT an address (offset + vtable info): int C::* is 8 bytes, void (C::*)() is 16 (and varies w/ inheritance on MSVC). Don't assume sizeof(ptr) == 8 when memcpy-ing or serializing callbacks.

3.4 What are the size guarantees of built-in types?

  • char: 1 byte
  • short: >= 16 bits
  • int: >= 16 bits (usually 32)
  • long: >= 32 bits
  • long long: >= 64 bits

3.5 Differences b/w pointers and references

Aspect Pointer Reference
Syntax int* p int& r
null can be null cannot be null
Reassignment Can point elsewhere Bound forever
Initialization Can be uninitialized Must be initialized
Indirection Explicit (*p) Implicit
Arithmetic Supported Not supported
sizeof Size of pointer Size of referenced type

3.6 Differences b/w malloc, new and operator::new

malloc new T new T[n] operator new operator new[]
Kind C library function Language expression Language expression C++ allocation function C++ allocation function
Returns void* T* T* (to first element) void* void*
Allocates raw memory yes via operator new via operator new[] yes yes
Runs constructors no yes (one) yes (n, in order) no no
Runs destructors on release no delete does delete[] does (reverse order) no no
Size argument you compute bytes compiler: sizeof(T) compiler: n*sizeof(T) + overhead you compute bytes you compute bytes
Element count known at release n/a n/a yes — stored in a "cookie" n/a n/a
On failure returns NULL throws std::bad_alloc throws std::bad_alloc, or std::bad_array_new_length throws std::bad_alloc throws std::bad_alloc
Nothrow form n/a (already null) new (std::nothrow) T new (std::nothrow) T[n] operator new(n, nothrow) operator new[](n, nothrow)
Overloadable / replaceable no no (dispatches to operator new) no (dispatches to operator new[]) yes (global + per-class) yes (global + per-class)
Alignment guarantee alignof(std::max_align_t) picks aligned overload automatically picks aligned overload automatically over-aligned overload since C++17 over-aligned overload since C++17
Value-initialization no new T() / new T{} new T[n]() zero-inits no no
Runtime-sized length allowed yes n/a yes (unlike C arrays) yes yes
Resizable realloc no no no no
Must pair with free delete delete[] operator delete operator delete[]
Mixing pairs UB UB UB UB UB

3.7 What is a smart pointer?

RAII wrapper that automatically manages memory

Type Ownership Use case
std::unique_ptr Exclusive Single owner, no copy
std::shared_ptr Shared Multiple owners, ref counted
std::weak_ptr Non-owning Break circular reference

3.8 How does std::unique_ptr work?

  • exclusive ownership: only one pointer owns the object
  • non-copyable, only movable
  • deletes object when destroyed or reset

3.9 How does std::shared_ptr work?

  • shared ownership: multiple pointers can own the same object
  • reference counting: tracks number of owners
  • object deleted when last pointer destroyed

Control block stores:

  • reference count (shared_ptr count)
  • weak count (weak_ptr count)
  • deleter
  • allocator

Cost:

  • larger than raw pointer
  • atomic ref count operations

3.10 How do you pass by value, reference, and pointer?

Method Syntax Copy? Modify original? Move?
Value void f(int x) Y N N
lvalue ref void f(int &x) N Y N
rvalue ref void f(int &&x) N Y Y
Const ref void f(const int& x) N N N
Pointer void f(int* x) N (ptr copy) Y N

3.11 What does std::move do?

  • it doesn't move anything
  • it casts: std::move casts its argument to rvalue reference &&
  • the cast selects a move ctor or move assignment

3.12 What are lvalue, rvalue, and forwarding references?

T& (lvalue ref) const T& T&& (rvalue ref)
binds to lvalues Y Y N
binds to rvalues (temporaries, std::move) N Y Y
can modify through it Y N Y
extends lifetime of a bound temp N/A Y Y
says about referent "someone else owns this" "only reading it" "this is expiring"
typical use out-param, mutating access read-only param, cheap default move ctor/assign, sink params
overload preferred for an rvalue arg - loses to T&& wins

Gotchas:

  • a named rvalue reference is an lvalue
    • T&& rhs is a variable w/ a name & an address
    • expression rhs is an lvalue
    • use std::move(rhs)
  • T&& on a deduced template parameter is a forwarding reference, not rvalue reference
    • collapses to T& when caller passes an lvalue
    • binds to both
    • use std::forward<T>, not std::move

3.13 What is the difference b/w stack & heap?

Aspect Stack Heap
Allocation Automatic Manual (new/malloc)
Deallocation Automatic (scope exit) Manual (delete/free)
Speed Very fast (ptr move) Slower (search free block)
Size Limited (1-8MB) Large (RAM)
Growth Downward Upward
Fragmentation None Possible
Access LIFO Random
Threads Own Shared

3.14 Memory diagram

stack segment (data local to functions)
- - - - - - -
|
V

the hole

^
|
- - - - - - -
the heap (used for malloc())
-------------
BSS segment (uninitialized data: global/static vars init. to 0 or not init.)
-
data segment (initialized data: global/static vars init. to non-zero)
-------------
text segment (instructions)

3.15 What is a ptr to a function used for?

Uses:

  • callbacks
  • plugin systems
  • state machines
  • polymorphism in C

3.16 What happens w/o delete/free?

Memory leak: memory stays allocated but inaccessible

When freed:

  • never during program execution
  • program termination: OS reclaims all process memory
  • long-running programs can exhaust all memory

3.17 What happens if you return a ref to a temp object?

Undefined Behavior (UB): dangling reference

Exceptions:

  • returning ref to static/global is OK
  • returning ref to member is OK (if obj outlives)
  • returning const ref to temp extends lifetime (in caller)

4. STL

4.1 What's the difference b/w std::set, std::map, std::unordered_map, std::unordered_multimap?

Container Implementation Sorted Duplicates Key-Value
set Red-black tree Y N Key only
map Red-black tree Y N Key-Value
unordered_map Hash table N N Key-Value
unordered_multimap Hash table N Y Key-Value

4.2 What's the difference b/w std::map & std::unordered_map?

std::map std::unordered_map
Red-black tree Hash table
O(log n) ops O(1) average
Sorted by key No order
Stable iterators May invalidate
No hash function needed Requires hash

4.3 What's the difference b/w std::vector & std::list?

Aspect std::vector std::list
Memory Contiguous Scattered nodes
Cache Cache-friendly Cache-unfriendly
Access O(1) random O(n)
Insert front O(n) O(1)
Insert middle O(n) O(1) w/ iterator
Insert back O(1) amortized O(1)
Memory overhead Low High (pointers)

Use vector when:

  • random access needed
  • mostly appending
  • cache performance matters
  • default choice

Use list when:

  • frequent insert/erase in middle
  • never need random access
  • iterator stability critical

5. Multi-threading

5.1 What is C++ threading support?

Since C++11:

  • std::thread: thread management
  • std::mutex, std::lock_guard: synchronization
  • std::condition_variable: signaling
  • std::atomic: lock-free ops
  • std::async, std::future: async tasks

Key concepts:

  • threads share memory (heap, global)
  • each thread has own stack
  • need synchronization for shared data
  • challenges: race conditions, deadlocks, data races

5.2 What's the difference b/w processes & threads

Aspect Process Thead
Memory Isolated Shared (within process)
Creation Heavy (fork, exec) Light
Communication IPC (pipes, sockets) Direct memory access
Crash impact Isolated Crashes whole process
Context switch Expensive Cheaper
Resources Own file descriptors Shared

Common:

  • both execute code
  • scheduled by OS
  • have execution state

5.3 How to synchronize information transfer b/w theads?

Mechanisms:

  • mutex: mutual exclusion
std::mutex mtx;
mtx.lock();
// critical section
mtx.unlock();
  • condition variable: wait/notify
std::condition_variable cv;
cv.wait(lock, [] { return ready; });
cv.notify_one();
  • atomic: lock-free
std::atomic<int> counter{0};
counter++;
  • futures/promises
std::promise<int> p;
auto f = p.get_future();
p.set_value(42);
int result = f.get();

5.4 What's the difference b/w mutex & semaphore?

Mutex Semaphore
Binary (locked/unlocked) Counter (0 to N)
Owned by thread No ownership
Must unlock from same thread Any thread can signal
Single resource Multiple resources

Mutex: only 1 thread in critical section

std::mutex m;
std::lock_guard<std::mutex> lock(m);

Semaphore (C++20):

std::counting_semaphore<3> sem(3);  // 3 permits
sem.acquire(); // -1
// do something
sem.release(); // +1

5.5 What is a deadlock?

Deadlock: threads wiating forever for each other.

Conditions (all must be true):

  • Mutual exclusion
  • Hold and wait
  • No preemption
  • Circular wait

Prevention:

  • lock in consistent order
  • use std::lock() for multiple mutexes
  • timeout on locks
  • avoid nested locks

5.6 How to avoid race conditions?

  • mutex/lock
  • atomic
  • avoid sharing
    • thread-local storage
    • message passing
  • immutable data
  • lock-free algos

Language Features

C++11

Feature Description with Examples
auto type inference Deduce a variable's type from its initializer. auto x = 42; (int), auto it = v.begin();
Range-based for Iterate a container directly. for (auto& e : v) e *= 2;
Lambda expressions Inline anonymous functions with capture. auto add = [](int a, int b){ return a + b; }; [=]/[&] capture by value/ref
Move semantics / rvalue refs Steal resources instead of copying via T&&. std::vector<int> b = std::move(a); std::move, std::forward
Smart pointers RAII ownership. auto p = std::make_shared<T>();, std::unique_ptr<T>, std::weak_ptr<T>
nullptr Type-safe null pointer literal replacing NULL/0. int* p = nullptr;
constexpr Compile-time evaluated functions/values. constexpr int sq(int x){ return x*x; } constexpr int n = sq(5);
Uniform initialization Brace init for any type. std::vector<int> v{1,2,3}; Point p{1,2}; plus std::initializer_list
enum class Scoped, strongly-typed enums. enum class Color { Red, Green }; Color::Red (no implicit int conversion)
Variadic templates Templates with any number of args. template<typename... Args> void f(Args... a);
decltype Deduce type of an expression. decltype(x + y) z;
static_assert Compile-time assertion. static_assert(sizeof(int) == 4, "msg");
override / final Explicit virtual override / prevent overriding. void f() override; class C final {};
= default / = delete Force or forbid compiler-generated members. C(const C&) = delete; ~C() = default;
Alias templates (using) Template-friendly typedefs. template<class T> using Vec = std::vector<T>;
noexcept Declare a function won't throw. void f() noexcept;
Trailing return type auto f(int x) -> int; (enables decltype on params)
Threading library std::thread, std::mutex, std::atomic<int>, std::condition_variable, std::async, std::future
New containers std::unordered_map/unordered_set (hash), std::array<int,5>, std::forward_list, std::tuple
std::function Type-erased callable wrapper. std::function<int(int)> f = sq;
User-defined literals constexpr long double operator""_km(long double x){ return x*1000; } 2.0_km

C++14

Feature Description with Examples
Generic lambdas auto params in lambdas. auto f = [](auto a, auto b){ return a + b; };
Lambda init capture Capture with initializer (move into lambda). [p = std::move(ptr)]{ ... }
Return type deduction auto return for regular functions. auto add(int a, int b){ return a + b; }
Variable templates Templated variables. template<class T> constexpr T pi = T(3.1415926); pi<double>
Relaxed constexpr Loops/locals/multiple statements allowed in constexpr functions
std::make_unique auto p = std::make_unique<T>(args); (the C++11 omission)
Binary literals int mask = 0b1010;
Digit separators int big = 1'000'000;
[[deprecated]] Attribute to mark deprecated APIs. [[deprecated("use g()")]] void f();

C++17

Feature Description with Examples
Structured bindings Destructure tuples/structs/pairs. auto [k, v] = *m.begin(); auto& [x, y] = point;
Init in if/switch Scope a variable to the condition. if (auto it = m.find(k); it != m.end()) { ... }
if constexpr Compile-time branch pruning. if constexpr (std::is_integral_v<T>) { ... }
Fold expressions Reduce variadic packs. template<class... A> auto sum(A... a){ return (a + ...); }
std::optional Maybe-a-value. std::optional<int> o; if (o) use(*o); o.value_or(0)
std::variant Type-safe union. std::variant<int,std::string> v = "hi"; std::get<std::string>(v), std::visit
std::any Type-erased single value. std::any a = 5; std::any_cast<int>(a);
std::string_view Non-owning string reference (no copy). void f(std::string_view s);
CTAD Class template arg deduction. std::pair p(1, "a"); std::vector v{1,2,3}; (no explicit <...>)
Inline variables Define vars in headers. inline int counter = 0;
std::filesystem Portable FS ops. std::filesystem::exists(p); for (auto& e : fs::directory_iterator(dir))
Parallel algorithms Execution policies. std::sort(std::execution::par, v.begin(), v.end());
Nested namespaces namespace a::b::c { ... }
Guaranteed copy elision T x = T(T(T())); constructs in place, no copies/moves
Attributes [[nodiscard]], [[maybe_unused]], [[fallthrough]]

C++20

Feature Description with Examples
Concepts Named constraints on templates. template<std::integral T> void f(T); requires clauses
Ranges Composable views/pipelines. auto r = v | std::views::filter(even) | std::views::transform(sq);
Coroutines Suspendable functions. co_await, co_yield, co_return (generators, async)
Modules Replace headers. export module math; import math; (faster builds, no macros leak)
Spaceship <=> Three-way comparison, auto-generates operators. auto operator<=>(const T&) const = default;
Designated initializers Init by member name. Point p{.x = 1, .y = 2};
consteval / constinit Immediate (must-be-compile-time) functions / guaranteed static init. consteval int f();
std::span Non-owning view over contiguous memory. void f(std::span<int> s);
std::format Python-style formatting. std::format("{} + {} = {}", a, b, a+b)
Calendar / time zones std::chrono::year_month_day, std::chrono::zoned_time
std::jthread Auto-joining thread with stop token. std::jthread t([]{ ... });
[[likely]] / [[unlikely]] Branch-prediction hints. if (x) [[likely]] { ... }

C++23

Feature Description with Examples
std::expected Value-or-error return type. std::expected<int, Error> r; if (r) use(*r); else use(r.error());
std::print / println Direct formatted output. std::println("{} items", n);
Deducing this Explicit object parameter (unifies const/ref overloads). auto f(this Self&& self){ ... }
if consteval Branch on compile-time vs runtime context. if consteval { ... } else { ... }
std::mdspan Multidimensional array view. std::mdspan m(data, rows, cols); m[i, j];
Multidim subscript operator[] with multiple args. m[i, j, k]
Flat containers Cache-friendly sorted containers. std::flat_map<K,V>, std::flat_set
std::generator Coroutine-based lazy range. std::generator<int> ints(){ for(int i=0;;++i) co_yield i; }
std::stacktrace Capture call stack. std::stacktrace::current()
Ranges additions std::ranges::to<std::vector>(), views::zip, views::enumerate, views::chunk

C++11 → C++20 by Feature

Feature Area C++11 C++14 C++17 C++20
Type deduction auto, decltype, trailing return types auto f() -> int Generic lambdas [](auto x){}, return type deduction auto f() Structured bindings auto [a,b] = pair;, CTAD vector v{1,2,3} Concepts template<std::integral T>, abbreviated function templates void f(auto x)
Templates Variadic templates template<typename... Args>, static_assert Variable templates template<class T> constexpr T pi = ... if constexpr, fold expressions (args + ...) Concepts replace SFINAE, consteval, non-type template params accept floats/strings
Compile-time constexpr (single return statement only), static_assert Relaxed constexpr (loops, local vars) constexpr if, inline variables constexpr vector/string/dynamic alloc, consteval, constinit
Lambdas Lambdas introduced [&](int x){ return x; } Generic lambdas, generalized captures [x = std::move(y)] Constexpr lambdas, capture *this by value Template lambdas []<typename T>(T x){}, lambdas in unevaluated contexts
Move semantics / memory Move semantics, rvalue refs &&, std::move, std::forward, std::unique_ptr, std::shared_ptr std::make_unique — std::span (non-owning view)
String/formatting Raw string literals R"(...)", std::to_string ""s string literal std::string_view std::format("{} = {}", k, v)
Containers/types std::array, std::tuple, std::unordered_map/set, std::chrono std::integer_sequence std::optional, std::variant, std::any, std::string_view std::span, calendar/timezone chrono, std::source_location
Algorithms/ranges std::begin/end, std::all_of/any_of/none_of Minor additions std::clamp, parallel STL (std::execution::par) Ranges library + views with pipe | composition, projections
Concurrency std::thread, std::mutex, std::condition_variable, std::future/promise, std::atomic std::shared_mutex (timed) std::shared_mutex, std::scoped_lock std::jthread, stop_token, coroutines (co_await), std::latch, std::barrier, std::counting_semaphore
Initialization Uniform init {}, initializer lists, in-class member init — Aggregate init extensions Designated initializers {.x=1, .y=2}
Enums/classes enum class (scoped enums), override/final, delegating constructors, = delete/= default — — using enum, spaceship <=> auto-generates all 6 comparison operators
Filesystem/IO — — <filesystem> library —
Modules/includes — — — import std; replaces headers
Attributes — [[deprecated]] [[nodiscard]], [[maybe_unused]], [[fallthrough]] [[nodiscard("reason")]], [[likely]]/[[unlikely]]
Other highlights Range-based for, nullptr, type aliases using, noexcept, user-defined literals Binary literals 0b1010, digit separators 1'000'000 Nested namespaces A::B::C, std::byte Modules, three-way comparison

The Evolution in a Nutshell

C++11 — The rebirth. Move semantics, lambdas, auto, smart pointers, threads, and uniform initialization made C++ a modern language. Nearly everything after builds on this foundation.

C++14 — Polish on C++11. Generic lambdas and relaxed constexpr are the standouts.

C++17 — The "practical utilities" release. optional, variant, string_view, structured bindings, if constexpr, <filesystem>, and parallel algorithms.

C++20 — The biggest leap since C++11. Concepts, ranges, coroutines, modules, and std::format fundamentally change how modern C++ is written.