Table of Contents generated with DocToc
1.1 How does static affect a variable?
staticglobal variables- internal linkage: visible in current translation unit
- prevents name conflicts with other files
staticlocal 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 here1.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'tstatic_cast: free, you guarantee the typedynamic_cast: runtime check, polymorphic types only (>= 1 virtual fn); ptr ->nullptron failure, ref -> throwsstd::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
constis 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/volatileon value params
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
throwwhile moving!
- no
- 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
constmethods)
2.9 What are const methods used for?
Only const member functions can be called by const objects.
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 tointint**: ptr to ptr tointvoid*: generic ptrnullptr: 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 byteshort: >= 16 bitsint: >= 16 bits (usually 32)long: >= 32 bitslong 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_ptrcount) - weak count (
weak_ptrcount) - 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::movecasts 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&& rhsis a variable w/ a name & an address- expression
rhsis 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>, notstd::move
- collapses to
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.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.1 What is C++ threading support?
Since C++11:
std::thread: thread managementstd::mutex,std::lock_guard: synchronizationstd::condition_variable: signalingstd::atomic: lock-free opsstd::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(); // +15.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
| 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 |
| 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(); |
| 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]] |
| 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]] { ... } |
| 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 |
| 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 |
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.