All information verified against cppreference.com (the authoritative C++ reference).
#include <algorithm>
#include <numeric>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// for_each
std::for_each(v.begin(), v.end(), [](int& x) { x *= 2; });
// v = {2, 4, 6, 8, 10}
// find
auto it = std::find(v.begin(), v.end(), 6);
if (it != v.end()) std::cout << "Found: " << *it << "\n"; // 6
// count
int n = std::count(v.begin(), v.end(), 4);
std::cout << "Count: " << n << "\n"; // 1
// accumulate (header: <numeric>)
int sum = std::accumulate(v.begin(), v.end(), 0);
std::cout << "Sum: " << sum << "\n"; // 30
}#include <algorithm>
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1, 2, 3, 4, 5};
// transform
std::vector<int> result(v.size());
std::transform(v.begin(), v.end(), result.begin(),
[](int x) { return x * x; });
// result = {1, 4, 9, 16, 25}
// copy
std::vector<int> dest(3);
std::copy(v.begin(), v.begin() + 3, dest.begin());
// move (algorithm, not std::move the utility)
std::vector<std::string> src = {"hello", "world"};
std::vector<std::string> dst(src.size());
std::move(src.begin(), src.end(), dst.begin());
// remove_if (erase-remove idiom)
std::vector<int> v2 = {1, 2, 3, 2, 5, 2};
v2.erase(std::remove_if(v2.begin(), v2.end(),
[](int x) { return x == 2; }), v2.end());
// v2 = {1, 3, 5}
}#include <mutex>
#include <thread>
#include <vector>
#include <iostream>
std::mutex mtx;
int counter = 0;
void increment() {
std::lock_guard<std::mutex> lock(mtx); // RAII lock, unlocks on scope exit
++counter;
}
// std::scoped_lock (C++17): can lock multiple mutexes at once (deadlock-free)
std::mutex m1, m2;
void transfer() {
std::scoped_lock lock(m1, m2); // locks both atomically
}
int main() {
std::vector<std::jthread> threads;
for (int i = 0; i < 10; ++i)
threads.emplace_back(increment);
std::cout << "Counter: " << counter << "\n"; // 10 (always correct)
}#include <atomic>
#include <thread>
#include <iostream>
std::atomic<int> counter{0};
void increment() {
for (int i = 0; i < 10000; ++i)
counter.fetch_add(1, std::memory_order_relaxed);
}
int main() {
std::thread t1(increment), t2(increment);
t1.join(); t2.join();
std::cout << "Counter: " << counter << "\n"; // 20000 (always correct)
}Memory Orderings (from ):
| Ordering | Description |
|---|---|
| memory_order_relaxed | Atomicity only; no ordering constraints. Good for counters. |
| memory_order_acquire | No reads/writes in current thread can be reordered before this load. |
| memory_order_release | No reads/writes in current thread can be reordered after this store. |
| memory_order_acq_rel | Both acquire (on load) and release (on store). For RMW operations. |
| memory_order_seq_cst | Default. Single total order across all threads. Strongest guarantee. |
| memory_order_consume | Deprecated (C++26). Like acquire but only for data-dependent operations. |
Release-Acquire Pattern:
#include <atomic>
#include <thread>
#include <string>
#include <cassert>
std::atomic<std::string*> ptr;
int data;
void producer() {
std::string* p = new std::string("Hello");
data = 42;
ptr.store(p, std::memory_order_release); // all prior writes visible
}
void consumer() {
std::string* p2;
while (!(p2 = ptr.load(std::memory_order_acquire)))
;
assert(*p2 == "Hello"); // guaranteed
assert(data == 42); // guaranteed (released before the store)
}
int main() {
std::thread t1(producer), t2(consumer);
t1.join(); t2.join();
}Data Race / Happens-Before:
- A data race occurs when two threads access the same memory location, at least one writes, and there is no happens-before relationship.
- happens-before is the fundamental ordering guarantee: if A happens-before B, then A's effects are visible to B.
- Atomic operations with sufficient ordering (acquire/release, seq_cst) establish happens-before relationships.
- Without synchronization, the compiler and CPU may reorder operations freely.
std::atomic_flag (header: ): Lock-free boolean atomic; the only type guaranteed lock-free on all implementations.
#include <atomic>
#include <thread>
#include <iostream>
std::atomic_flag flag = ATOMIC_FLAG_INIT;
void spinlock_acquire() {
while (flag.test_and_set(std::memory_order_acquire)) // spin
;
}
void spinlock_release() {
flag.clear(std::memory_order_release);
}
int main() {
std::thread t1([]{
spinlock_acquire();
std::cout << "Thread 1 in critical section\n";
spinlock_release();
});
std::thread t2([]{
spinlock_acquire();
std::cout << "Thread 2 in critical section\n";
spinlock_release();
});
t1.join(); t2.join();
}A general-purpose polymorphic function wrapper. Can store functions, lambdas, bind expressions, function objects, and member function pointers.
#include <functional>
#include <iostream>
int add(int a, int b) { return a + b; }
struct Multiplier {
int factor;
int operator()(int x) const { return x * factor; }
};
int main() {
// Store a free function
std::function<int(int, int)> f = add;
std::cout << f(3, 4) << "\n"; // 7
// Store a lambda
std::function<int(int)> square = [](int x) { return x * x; };
std::cout << square(5) << "\n"; // 25
// Store a function object
std::function<int(int)> mul = Multiplier{10};
std::cout << mul(5) << "\n"; // 50
// Check if empty
std::function<void()> empty;
if (!empty) std::cout << "Empty function\n";
// Calling empty throws std::bad_function_call
// Capture variables in lambda
int offset = 100;
std::function<int(int)> add_offset = [offset](int x) { return x + offset; };
}#include <functional>
#include <iostream>
void greet(std::string greeting, std::string name) {
std::cout << greeting << ", " << name << "!\n";
}
int main() {
// std::bind
using namespace std::placeholders;
auto hello = std::bind(greet, "Hello", _1);
hello("World"); // Hello, World!
// Modern alternative: lambda (generally preferred)
auto goodbye = [](std::string name) { greet("Goodbye", name); };
goodbye("World");
// C++20: std::bind_front (preferred over bind for partial application)
auto hi = std::bind_front(greet, "Hi");
hi("Everyone"); // Hi, Everyone!
}#include <bit>
#include <bitset>
#include <cstdint>
#include <iostream>
int main() {
uint32_t x = 0b00000000000000000000000101100000u;
// Population count (number of set bits)
std::cout << "popcount: " << std::popcount(x) << "\n"; // 3
// Count leading zeros (from MSB)
std::cout << "countl_zero: " << std::countl_zero(x) << "\n"; // 25
// Count leading ones
// Count trailing zeros (from LSB)
std::cout << "countr_zero: " << std::countr_zero(x) << "\n"; // 5
// Count trailing ones
// Bit width (number of bits needed to represent x)
std::cout << "bit_width: " << std::bit_width(x) << "\n"; // 7
// Powers of 2
std::cout << "has_single_bit: " << std::has_single_bit(8u) << "\n"; // true (power of 2)
std::cout << "bit_ceil(5): " << std::bit_ceil(5u) << "\n"; // 8
std::cout << "bit_floor(5): " << std::bit_floor(5u) << "\n"; // 4
// Rotate
uint8_t val = 0b11000011;
std::cout << "rotl: " << std::bitset<8>(std::rotl(val, 2)) << "\n"; // 00001111
std::cout << "rotr: " << std::bitset<8>(std::rotr(val, 2)) << "\n"; // 11110000
// Endianness
if constexpr (std::endian::native == std::endian::little)
std::cout << "Little endian\n";
}A type-safe, performant replacement for printf and iostreams. Compile-time format string checking.
#include <format>
#include <iostream>
#include <string>
int main() {
// Basic formatting
std::cout << std::format("Hello {}!\n", "world");
// Positional arguments
std::cout << std::format("{1} {0}\n", "World", "Hello"); // "Hello World"
// Number formatting
std::cout << std::format("Int: {:d}\n", 42); // Int: 42
std::cout << std::format("Hex: {:x}\n", 255); // Hex: ff
std::cout << std::format("Hex: {:X}\n", 255); // Hex: FF
std::cout << std::format("Oct: {:o}\n", 255); // Oct: 377
std::cout << std::format("Bin: {:b}\n", 255); // Bin: 11111111
// Float formatting
std::cout << std::format("Pi: {:.4f}\n", 3.14159); // Pi: 3.1416
std::cout << std::format("Sci: {:.2e}\n", 1234.5); // Sci: 1.23e+03
// Width and alignment
std::cout << std::format("|{:>10}|\n", "right"); // | right|
std::cout << std::format("|{:<10}|\n", "left"); // |left |
std::cout << std::format("|{:^10}|\n", "center"); // | center |
std::cout << std::format("|{:*^10}|\n", "center"); // |**center**|
// Fill with zeros
std::cout << std::format("Zero-padded: {:05d}\n", 42); // 00042
// String formatting
std::string name = "C++";
int version = 20;
std::cout << std::format("{} {}\n", name, version); // C++ 20
// Dynamic format string (runtime)
std::string fmt_str = "Value: {}\n";
std::cout << std::vformat(fmt_str, std::make_format_args(42));
}Format spec overview:
{[arg-id]:[fill][align][sign][#][0][width][.precision][L][type]}
| Specifier | Meaning |
|---|---|
d |
Decimal integer |
x / X |
Hexadecimal |
o |
Octal |
b |
Binary |
e / E |
Scientific float |
f / F |
Fixed-point float |
g / G |
General float |
s |
String |
p |
Pointer |
All technical details verified against the following cppreference.com pages:
- https://en.cppreference.com/w/cpp/container/vector
- https://en.cppreference.com/w/cpp/container/map
- https://en.cppreference.com/w/cpp/container/unordered_map
- https://en.cppreference.com/w/cpp/container/deque
- https://en.cppreference.com/w/cpp/container/list
- https://en.cppreference.com/w/cpp/container/set
- https://en.cppreference.com/w/cpp/container/array
- https://en.cppreference.com/w/cpp/iterator
- https://en.cppreference.com/w/cpp/ranges
- https://en.cppreference.com/w/cpp/thread/thread
- https://en.cppreference.com/w/cpp/thread/jthread
- https://en.cppreference.com/w/cpp/atomic/atomic
- https://en.cppreference.com/w/cpp/atomic/memory_order
- https://en.cppreference.com/w/cpp/utility/optional
- https://en.cppreference.com/w/cpp/utility/expected
- https://en.cppreference.com/w/cpp/utility/variant
- https://en.cppreference.com/w/cpp/utility/format/format
- https://en.cppreference.com/w/cpp/chrono
- https://en.cppreference.com/w/cpp/string/basic_string_view
- https://en.cppreference.com/w/cpp/container/span
- https://en.cppreference.com/w/cpp/utility/functional/function
- https://en.cppreference.com/w/cpp/utility/bitset
- https://en.cppreference.com/w/cpp/numeric/popcount