C++ STL Quick Reference Guide
A condensed cheat sheet for daily C++ development. Bookmark this page!
Container Selection Guide
Decision Tree
┌─────────────────────────────────────────────────────────────┐
│ WHICH CONTAINER SHOULD I USE? │
├─────────────────────────────────────────────────────────────┤
│ │
│ Need random access (by index)? │
│ ├─ YES ─> Fixed size? │
│ │ ├─ YES ─> std::array │
│ │ └─ NO ──> Fast insert/delete at ends? │
│ │ ├─ Back only ───> std::vector │
│ │ └─ Both ends ───> std::deque │
│ │ │
│ └─ NO ──> Need sorted order? │
│ ├─ YES ─> Unique keys? │
│ │ ├─ YES ─> Key only? │
│ │ │ ├─ YES ─> std::set │
│ │ │ └─ NO ──> std::map │
│ │ └─ NO ──> Key only? │
│ │ ├─ YES ─> std::multiset │
│ │ └─ NO ──> std::multimap │
│ │ │
│ └─ NO ──> Need fast lookup? │
│ ├─ YES ─> Unique keys? │
│ │ ├─ YES ─> Key only? │
│ │ │ ├─ YES ─> std::unordered_set│
│ │ │ └─ NO ──> std::unordered_map│
│ │ └─ NO ──> Key only? │
│ │ ├─ YES ─> std::unordered_multiset│
│ │ └─ NO ──> std::unordered_multimap│
│ │ │
│ └─ NO ──> Frequent insert/delete middle?│
│ ├─ YES ─> Forward only? │
│ │ ├─ YES ─> std::forward_list│
│ │ └─ NO ──> std::list│
│ └─ NO ──> std::vector │
│ │
│ Special cases: │
│ - LIFO (stack) ────────────────────> std::stack │
│ - FIFO (queue) ────────────────────> std::queue │
│ - Priority queue ──────────────────> std::priority_queue │
│ - Bits/flags ──────────────────────> std::bitset │
│ - String ──────────────────────────> std::string │
│ - Optional value ──────────────────> std::optional │
│ - One of several types ────────────> std::variant │
│ │
└─────────────────────────────────────────────────────────────┘
Time Complexity Quick Reference
┌────────────────────────────────────────────────────────────────────┐
│ OPERATION COMPLEXITY TABLE │
├────────────────────────────────────────────────────────────────────┤
│ Container │ Access │ Insert │ Delete │ Search │ Memory │
├─────────────────┼────────┼────────┼────────┼────────┼─────────────┤
│ vector │ O(1) │ O(n) │ O(n) │ O(n) │ Lowest │
│ │ │ O(1)* │ O(1)* │ │ │
│ deque │ O(1) │ O(n) │ O(n) │ O(n) │ Medium │
│ │ │ O(1)* │ O(1)* │ │ │
│ list │ O(n) │ O(1)** │ O(1)** │ O(n) │ High │
│ forward_list │ O(n) │ O(1)** │ O(1)** │ O(n) │ Lower │
│ array │ O(1) │ N/A │ N/A │ O(n) │ Lowest │
├─────────────────┼────────┼────────┼────────┼────────┼─────────────┤
│ set/map │ O(log n)│ O(log n)│ O(log n)│O(log n)│ Medium │
│ multiset/map │ O(log n)│ O(log n)│ O(log n)│O(log n)│ Medium │
├─────────────────┼────────┼────────┼────────┼────────┼─────────────┤
│ unordered_set │ N/A │ O(1)***│ O(1)***│ O(1)***│ High │
│ unordered_map │ O(1) │ O(1)***│ O(1)***│ O(1)***│ High │
├─────────────────┼────────┼────────┼────────┼────────┼─────────────┤
│ stack │ O(1)† │ O(1) │ O(1) │ N/A │ Low │
│ queue │ O(1)† │ O(1) │ O(1) │ N/A │ Low │
│ priority_queue │ O(1)† │ O(log n)│O(log n)│ N/A │ Low │
└────────────────────────────────────────────────────────────────────┘
* at back/front
** if you have iterator to position
*** average case, O(n) worst case
† top/front only
Most Common Algorithms - Quick Syntax
Sorting & Searching
// Sort
std::sort(v.begin(), v.end()); // Ascending
std::sort(v.begin(), v.end(), std::greater<>()); // Descending
std::sort(v.begin(), v.end(), [](auto& a, auto& b) { return a.x < b.x; });
// Partial sort (top N)
std::partial_sort(v.begin(), v.begin() + 10, v.end());
// Find
auto it = std::find(v.begin(), v.end(), value);
auto it = std::find_if(v.begin(), v.end(), [](auto& x) { return x > 10; });
// Binary search (requires sorted)
bool found = std::binary_search(v.begin(), v.end(), value);
auto it = std::lower_bound(v.begin(), v.end(), value); // First >= value
auto it = std::upper_bound(v.begin(), v.end(), value); // First > value
// Min/Max
auto min_it = std::min_element(v.begin(), v.end());
auto max_it = std::max_element(v.begin(), v.end());
auto [min_it, max_it] = std::minmax_element(v.begin(), v.end());
Modifying Sequences
// Copy
std::copy(src.begin(), src.end(), dest.begin());
std::copy_if(src.begin(), src.end(), dest.begin(), predicate);
// Transform
std::transform(v.begin(), v.end(), v.begin(), [](auto x) { return x * 2; });
// Remove (erase-remove idiom)
v.erase(std::remove(v.begin(), v.end(), value), v.end());
v.erase(std::remove_if(v.begin(), v.end(), predicate), v.end());
// Unique (remove consecutive duplicates - requires sorted)
std::sort(v.begin(), v.end());
v.erase(std::unique(v.begin(), v.end()), v.end());
// Reverse
std::reverse(v.begin(), v.end());
// Rotate
std::rotate(v.begin(), v.begin() + 3, v.end()); // Shift left by 3
// Fill
std::fill(v.begin(), v.end(), value);
std::fill_n(v.begin(), 10, value);
// Generate
std::generate(v.begin(), v.end(), []() { return rand(); });
Numeric Operations
// Sum
int sum = std::accumulate(v.begin(), v.end(), 0);
int sum = std::reduce(v.begin(), v.end(), 0); // C++17, parallel
// Product
int product = std::accumulate(v.begin(), v.end(), 1, std::multiplies<>());
// Inner product
int dot = std::inner_product(v1.begin(), v1.end(), v2.begin(), 0);
// Partial sum
std::partial_sum(v.begin(), v.end(), result.begin());
// Adjacent difference
std::adjacent_difference(v.begin(), v.end(), result.begin());
Counting & Testing
// Count
int n = std::count(v.begin(), v.end(), value);
int n = std::count_if(v.begin(), v.end(), predicate);
// All, any, none
bool all = std::all_of(v.begin(), v.end(), predicate);
bool any = std::any_of(v.begin(), v.end(), predicate);
bool none = std::none_of(v.begin(), v.end(), predicate);
// Equal
bool equal = std::equal(v1.begin(), v1.end(), v2.begin());
// Mismatch
auto [it1, it2] = std::mismatch(v1.begin(), v1.end(), v2.begin());
C++20 Ranges - Quick Syntax
#include <ranges>
namespace rng = std::ranges;
namespace vws = std::views;
// Filter
auto evens = v | vws::filter([](int x) { return x % 2 == 0; });
// Transform
auto doubled = v | vws::transform([](int x) { return x * 2; });
// Take/Drop
auto first10 = v | vws::take(10);
auto skip10 = v | vws::drop(10);
// Chain operations
auto result = v
| vws::filter([](int x) { return x > 0; })
| vws::transform([](int x) { return x * x; })
| vws::take(5);
// Ranges algorithms (no .begin()/.end() needed!)
rng::sort(v);
rng::find(v, value);
rng::copy(v, std::back_inserter(dest));
// With projections
rng::sort(people, {}, &Person::age); // Sort by age
Modern C++ Features Quick Reference
C++11
// Auto type deduction
auto x = 42;
auto ptr = std::make_unique<int>(42);
// Range-based for loop
for (const auto& item : container) { }
// Lambda expressions
auto lambda = [](int x) { return x * 2; };
auto capture = [&, x](int y) { return x + y; };
// Move semantics
std::vector<int> v2 = std::move(v1);
// Smart pointers
std::unique_ptr<T> ptr = std::make_unique<T>(args);
std::shared_ptr<T> ptr = std::make_shared<T>(args);
// nullptr
T* ptr = nullptr;
// Uniform initialization
std::vector<int> v{1, 2, 3, 4, 5};
// Deleted/defaulted functions
ClassName(const ClassName&) = delete;
ClassName() = default;
// override and final
void func() override;
void func() final;
C++14
// Generic lambdas
auto lambda = [](auto x) { return x * 2; };
// Lambda capture with initializers
auto lambda = [x = getValue()](){ return x; };
// make_unique
auto ptr = std::make_unique<T>(args);
// Return type deduction
auto func() { return 42; }
C++17
// Structured bindings
auto [x, y] = std::pair{1, 2};
auto [key, value] = *map.find("key");
// if with initializer
if (auto it = map.find(key); it != map.end()) { }
// if constexpr
if constexpr (condition) { } else { }
// std::optional
std::optional<int> opt = getValue();
if (opt) { use(*opt); }
// std::variant
std::variant<int, double, std::string> var = 42;
std::visit([](auto& x) { /* ... */ }, var);
// std::filesystem
std::filesystem::path p = "/path/to/file";
if (std::filesystem::exists(p)) { }
// Parallel algorithms
std::sort(std::execution::par, v.begin(), v.end());
C++20
// Concepts
template<std::integral T>
void func(T value) { }
// Ranges
auto result = v | std::views::filter(pred) | std::views::transform(fn);
// Coroutines
generator<int> range(int start, int end) {
for (int i = start; i < end; ++i) {
co_yield i;
}
}
// Three-way comparison (spaceship)
auto operator<=>(const T&) const = default;
// Designated initializers
Person p{.name = "John", .age = 30};
// consteval (immediate functions)
consteval int square(int x) { return x * x; }
// std::span
void func(std::span<int> data) { }
// std::format
std::string s = std::format("Hello, {}!", name);
C++23
// std::expected
std::expected<int, Error> result = compute();
if (result) { use(*result); }
// std::mdspan (multidimensional span)
std::mdspan<int, std::dextents<int, 2>> matrix(data, 3, 4);
// ranges::to
auto vec = range | std::ranges::to<std::vector>();
// std::print
std::print("Hello, {}!\n", name);
// Deducing this
struct S {
template<typename Self>
auto&& get(this Self&& self) { return std::forward<Self>(self).value; }
};
Common Patterns Quick Reference
RAII Pattern
class Resource {
public:
Resource() { /* acquire */ }
~Resource() { /* release */ }
// Rule of Five
Resource(const Resource&) = delete;
Resource& operator=(const Resource&) = delete;
Resource(Resource&&) noexcept = default;
Resource& operator=(Resource&&) noexcept = default;
};
// Usage
{
Resource r; // Automatically cleaned up
} // Destructor called here
Factory Pattern
class Product {
public:
virtual ~Product() = default;
virtual void use() = 0;
};
class Factory {
public:
static std::unique_ptr<Product> create(Type type) {
switch (type) {
case Type::A: return std::make_unique<ProductA>();
case Type::B: return std::make_unique<ProductB>();
}
}
};
// Usage
auto product = Factory::create(Type::A);
product->use();
Observer Pattern (Modern)
class Subject {
std::vector<std::function<void(int)>> observers_;
public:
void attach(std::function<void(int)> observer) {
observers_.push_back(std::move(observer));
}
void notify(int value) {
for (auto& observer : observers_) {
observer(value);
}
}
};
// Usage
Subject subject;
subject.attach([](int x) { std::cout << "Observer 1: " << x << "\n"; });
subject.attach([](int x) { std::cout << "Observer 2: " << x * 2 << "\n"; });
subject.notify(42);
Strategy Pattern (Modern)
class Context {
std::function<int(int, int)> strategy_;
public:
void set_strategy(std::function<int(int, int)> strategy) {
strategy_ = std::move(strategy);
}
int execute(int a, int b) {
return strategy_(a, b);
}
};
// Usage
Context ctx;
ctx.set_strategy([](int a, int b) { return a + b; });
std::cout << ctx.execute(5, 3) << "\n"; // 8
ctx.set_strategy([](int a, int b) { return a * b; });
std::cout << ctx.execute(5, 3) << "\n"; // 15
Singleton Pattern (Thread-Safe)
class Singleton {
public:
static Singleton& instance() {
static Singleton instance; // C++11 guarantees thread safety
return instance;
}
Singleton(const Singleton&) = delete;
Singleton& operator=(const Singleton&) = delete;
private:
Singleton() = default;
};
// Usage
auto& s = Singleton::instance();
Pimpl Idiom
// Header
class Widget {
public:
Widget();
~Widget();
void operation();
private:
class Impl;
std::unique_ptr<Impl> pimpl_;
};
// Implementation
class Widget::Impl {
// Private implementation details
};
Widget::Widget() : pimpl_(std::make_unique<Impl>()) {}
Widget::~Widget() = default; // Must be in .cpp for unique_ptr<Impl>
void Widget::operation() { pimpl_->do_something(); }
Performance Tips Quick Reference
Container Performance
// ✓ GOOD: Reserve capacity for vector
std::vector<int> v;
v.reserve(1000); // Avoid reallocations
for (int i = 0; i < 1000; ++i) {
v.push_back(i);
}
// ✗ BAD: Random access in list
std::list<int> lst;
auto it = lst.begin();
std::advance(it, 500); // O(n) - slow!
// ✓ GOOD: Use vector for random access
std::vector<int> vec;
int x = vec[500]; // O(1) - fast!
// ✓ GOOD: emplace instead of push
v.emplace_back(arg1, arg2); // Construct in-place
// ✗ BAD:
v.push_back(Object(arg1, arg2)); // Construct then move
// ✓ GOOD: Use unordered containers for large datasets
std::unordered_map<std::string, int> fast_lookup; // O(1)
// ✗ BAD:
std::map<std::string, int> slow_lookup; // O(log n)
Algorithm Performance
// ✓ GOOD: Use algorithm instead of hand-written loop
auto it = std::find(v.begin(), v.end(), value);
// ✗ BAD: Hand-written loop
for (size_t i = 0; i < v.size(); ++i) {
if (v[i] == value) { /* ... */ }
}
// ✓ GOOD: Parallel algorithms for large data
std::sort(std::execution::par, v.begin(), v.end());
// ✓ GOOD: Use ranges for composability without temporaries
auto result = v
| std::views::filter(pred)
| std::views::transform(fn);
// No intermediate containers created!
Move Semantics
// ✓ GOOD: Move instead of copy
std::vector<int> v2 = std::move(v1);
func(std::move(obj));
// ✓ GOOD: Return by value (NRVO/RVO)
std::vector<int> func() {
std::vector<int> result;
// ...
return result; // No std::move needed!
}
// ✗ BAD: Unnecessary copy
void func(std::string s) { // Copy!
// ...
}
// ✓ GOOD: Pass by const reference
void func(const std::string& s) { // No copy
// ...
}
// ✓ BEST: Use string_view for read-only strings
void func(std::string_view s) { // No copy, more flexible
// ...
}
Cache-Friendly Code
// ✓ GOOD: Contiguous memory (cache-friendly)
std::vector<int> v; // Elements stored contiguously
// ✗ BAD: Non-contiguous memory (cache-unfriendly)
std::list<int> lst; // Elements scattered in memory
// ✓ GOOD: Struct of Arrays (SoA) for large datasets
struct Players {
std::vector<int> health;
std::vector<int> mana;
std::vector<Position> positions;
};
// ✗ BAD: Array of Structs (AoS) when processing one field
struct Player {
int health;
int mana;
Position pos;
};
std::vector<Player> players;
Common Gotchas Checklist
Container Gotchas
// ✗ Iterator invalidation after modification
std::vector<int> v = {1, 2, 3};
auto it = v.begin();
v.push_back(4); // it is now INVALID!
// ✗ Modifying container while iterating
for (auto it = v.begin(); it != v.end(); ++it) {
v.erase(it); // it is now INVALID!
}
// ✓ CORRECT:
for (auto it = v.begin(); it != v.end(); ) {
it = v.erase(it); // Get new valid iterator
}
// ✗ Using [] on map creates entry
std::map<int, int> m;
int x = m[5]; // Creates entry with value 0!
// ✓ CORRECT:
auto it = m.find(5);
if (it != m.end()) {
int x = it->second;
}
// ✗ Assuming vector bool is like vector<T>
std::vector<bool> vb;
bool& ref = vb[0]; // ERROR! vector<bool> is specialized
// ✓ CORRECT: Use std::vector<char> or std::deque<bool>
OOP Gotchas
// ✗ Non-virtual destructor in base class
class Base {
~Base() {} // NOT virtual!
};
Base* ptr = new Derived();
delete ptr; // Derived destructor NOT called - memory leak!
// ✓ CORRECT:
class Base {
virtual ~Base() {}
};
// ✗ Object slicing
Derived d;
Base b = d; // Sliced! Only Base part copied
// ✓ CORRECT: Use pointers/references
Base& b = d;
// ✗ Calling virtual functions in constructor
class Base {
Base() { init(); } // Calls Base::init, not Derived::init!
virtual void init() {}
};
// ✗ Forgetting override keyword
class Derived : public Base {
void func() {} // Might not override Base::func()
};
// ✓ CORRECT:
void func() override {} // Compiler error if not overriding
Template Gotchas
// ✗ Most vexing parse
Widget w(); // Function declaration, not object!
// ✓ CORRECT:
Widget w; // Object
Widget w{}; // Also correct (uniform initialization)
// ✗ Missing typename in dependent types
template<typename T>
void func() {
T::value_type x; // ERROR if value_type is a type!
}
// ✓ CORRECT:
typename T::value_type x;
// ✗ Forgetting template keyword for dependent member templates
obj.template member<T>();
// ✗ Integer division in templates
template<int N>
struct X {
static constexpr int half = N / 2; // Integer division!
};
Move Semantics Gotchas
// ✗ std::move doesn't move!
std::vector<int> v1 = {1, 2, 3};
std::move(v1); // Does NOTHING! Just casts to rvalue
// ✓ CORRECT:
std::vector<int> v2 = std::move(v1); // Actually moves
// ✗ Using moved-from object
std::string s1 = "hello";
std::string s2 = std::move(s1);
std::cout << s1; // UB or unspecified behavior!
// ✗ Moving in return statement prevents RVO
std::vector<int> func() {
std::vector<int> v;
return std::move(v); // Prevents RVO! DON'T DO THIS!
}
// ✓ CORRECT:
return v; // Let compiler optimize
// ✗ Const objects can't be moved
const std::vector<int> v1 = {1, 2, 3};
std::vector<int> v2 = std::move(v1); // Copies, doesn't move!
Concurrency Gotchas
// ✗ Data race
int counter = 0;
std::thread t1([&]() { ++counter; }); // Race condition!
std::thread t2([&]() { ++counter; });
// ✓ CORRECT: Use mutex or atomic
std::atomic<int> counter{0};
std::thread t1([&]() { ++counter; });
std::thread t2([&]() { ++counter; });
// ✗ Deadlock
std::mutex m1, m2;
// Thread 1:
m1.lock(); m2.lock();
// Thread 2:
m2.lock(); m1.lock(); // DEADLOCK!
// ✓ CORRECT: Lock in same order or use scoped_lock
std::scoped_lock lock(m1, m2); // Deadlock-free
Quick Debugging Checklist
Before Code Review:
☐ Compiles with -Wall -Wextra -Werror
☐ No memory leaks (valgrind)
☐ All tests pass
☐ const-correctness verified
☐ Move semantics used where appropriate
☐ Smart pointers used (no raw new/delete)
☐ RAII for all resource management
☐ Virtual destructor in base classes
☐ override keyword used
☐ No iterator invalidation issues
☐ Thread-safe (if concurrent)
☐ Exception-safe (RAII)
☐ No unnecessary copies
☐ Proper use of auto
☐ Range-based for where possible
☐ Algorithms instead of raw loops
Container Operation Cheat Sheet
// Vector
v.push_back(x); // Add to end - O(1) amortized
v.pop_back(); // Remove from end - O(1)
v.insert(it, x); // Insert at position - O(n)
v.erase(it); // Erase at position - O(n)
v.reserve(n); // Reserve capacity - avoid reallocations
v.shrink_to_fit(); // Reduce capacity to size
v[i] // Access by index - O(1)
// Deque
d.push_back(x); // Add to end - O(1)
d.push_front(x); // Add to front - O(1)
d.pop_back(); // Remove from end - O(1)
d.pop_front(); // Remove from front - O(1)
// List
l.push_back(x); // Add to end - O(1)
l.push_front(x); // Add to front - O(1)
l.insert(it, x); // Insert at position - O(1) if you have iterator
l.erase(it); // Erase at position - O(1)
l.remove(x); // Remove all x - O(n)
l.sort(); // Sort list - O(n log n)
l.unique(); // Remove consecutive duplicates - O(n)
l.splice(it, other); // Move elements from other - O(1) or O(n)
// Set/Map
s.insert(x); // Insert - O(log n)
s.erase(x); // Erase - O(log n)
s.find(x); // Find - O(log n)
s.count(x); // Count - O(log n)
s.lower_bound(x); // First >= x - O(log n)
s.upper_bound(x); // First > x - O(log n)
// Unordered Set/Map
us.insert(x); // Insert - O(1) average
us.erase(x); // Erase - O(1) average
us.find(x); // Find - O(1) average
us.count(x); // Count - O(1) average
us.bucket_count(); // Number of buckets
us.load_factor(); // Elements / buckets
us.rehash(n); // Set bucket count to >= n
// Stack
stk.push(x); // Push - O(1)
stk.pop(); // Pop - O(1)
stk.top(); // Top element - O(1)
// Queue
q.push(x); // Push to back - O(1)
q.pop(); // Pop from front - O(1)
q.front(); // Front element - O(1)
q.back(); // Back element - O(1)
// Priority Queue
pq.push(x); // Push - O(log n)
pq.pop(); // Pop - O(log n)
pq.top(); // Top element - O(1)
// String
s.append(str); // Append - O(n)
s.substr(pos, len); // Substring - O(n)
s.find(str); // Find - O(n*m)
s.replace(pos, len, str);// Replace - O(n)
s += str; // Concatenate - O(n)
Common Type Traits
// Type checks
std::is_integral_v<T>
std::is_floating_point_v<T>
std::is_arithmetic_v<T>
std::is_pointer_v<T>
std::is_reference_v<T>
std::is_const_v<T>
std::is_class_v<T>
std::is_enum_v<T>
std::is_function_v<T>
std::is_array_v<T>
// Type properties
std::is_trivial_v<T>
std::is_standard_layout_v<T>
std::is_pod_v<T>
std::is_empty_v<T>
std::is_polymorphic_v<T>
std::is_abstract_v<T>
std::is_final_v<T>
// Type relationships
std::is_same_v<T, U>
std::is_base_of_v<Base, Derived>
std::is_convertible_v<From, To>
// Type transformations
std::remove_const_t<T>
std::remove_reference_t<T>
std::remove_cv_t<T>
std::add_const_t<T>
std::add_pointer_t<T>
std::decay_t<T>
std::underlying_type_t<Enum>
// Conditional
std::conditional_t<condition, T, U>
std::enable_if_t<condition, T>
Lambda Syntax Quick Reference
// Basic lambda
auto lambda = []() { return 42; };
// With parameters
auto add = [](int a, int b) { return a + b; };
// Capture by value
int x = 10;
auto f1 = [x]() { return x; };
// Capture by reference
auto f2 = [&x]() { x++; };
// Capture all by value
auto f3 = [=]() { return x + y; };
// Capture all by reference
auto f4 = [&]() { x++; y++; };
// Mixed capture
auto f5 = [&, x]() { y++; return x; }; // x by value, rest by ref
auto f6 = [=, &x]() { x++; return y; }; // x by ref, rest by value
// Capture with initialization (C++14)
auto f7 = [x = getValue()]() { return x; };
auto f8 = [ptr = std::make_unique<int>(42)]() { return *ptr; };
// Mutable lambda
auto f9 = [x]() mutable { return ++x; };
// Generic lambda (C++14)
auto f10 = [](auto x, auto y) { return x + y; };
// Template lambda (C++20)
auto f11 = []<typename T>(T x, T y) { return x + y; };
// Return type specification
auto f12 = [](int x) -> double { return x * 1.5; };
// Trailing return type with decltype
auto f13 = [](auto x, auto y) -> decltype(x + y) { return x + y; };
// Immediate invocation
int result = []() { return 42; }();
// In algorithms
std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
std::transform(v.begin(), v.end(), v.begin(), [](int x) { return x * 2; });
Smart Pointer Quick Reference
// unique_ptr - exclusive ownership
std::unique_ptr<T> ptr = std::make_unique<T>(args);
std::unique_ptr<T> ptr(new T(args)); // Less preferred
ptr.reset(new T(args)); // Reset with new object
ptr.reset(); // Delete and set to nullptr
T* raw = ptr.get(); // Get raw pointer (doesn't transfer ownership)
T* raw = ptr.release(); // Release ownership (must delete manually)
auto ptr2 = std::move(ptr); // Transfer ownership
// shared_ptr - shared ownership
std::shared_ptr<T> ptr = std::make_shared<T>(args);
std::shared_ptr<T> ptr(new T(args)); // Less preferred (2 allocations)
std::shared_ptr<T> ptr2 = ptr; // Both own the object
long count = ptr.use_count(); // Reference count
ptr.reset(); // Decrement refcount
// weak_ptr - non-owning reference
std::weak_ptr<T> weak = shared;
if (auto ptr = weak.lock()) { // Try to get shared_ptr
// Use ptr - object still exists
}
bool expired = weak.expired(); // Check if object deleted
// Custom deleter
auto deleter = [](T* ptr) {
custom_cleanup(ptr);
delete ptr;
};
std::unique_ptr<T, decltype(deleter)> ptr(new T, deleter);
std::shared_ptr<T> ptr2(new T, deleter);
// Arrays
std::unique_ptr<T[]> arr = std::make_unique<T[]>(size);
arr[0] = value; // Operator[] available
std::shared_ptr<T[]> arr2(new T[size]); // C++17
// Or better: use std::vector
Commonly Used Utilities
// std::optional
std::optional<int> opt = getValue();
if (opt.has_value()) {
int x = *opt;
int y = opt.value(); // Throws if empty
}
int z = opt.value_or(42); // Default if empty
// std::variant
std::variant<int, double, std::string> var = 42;
std::holds_alternative<int>(var); // true
int x = std::get<int>(var); // Get by type
int y = std::get<0>(var); // Get by index
std::visit([](auto&& arg) { // Visit with lambda
std::cout << arg;
}, var);
// std::any
std::any a = 42;
a = std::string("hello");
if (a.has_value()) {
std::string s = std::any_cast<std::string>(a);
}
// std::tuple
std::tuple<int, double, std::string> t{1, 3.14, "hello"};
int x = std::get<0>(t);
auto [a, b, c] = t; // Structured binding
// std::pair
std::pair<int, std::string> p{42, "hello"};
int x = p.first;
std::string s = p.second;
auto [key, value] = p; // Structured binding
// std::tie (for unpacking)
int a; double b;
std::tie(a, b) = std::tuple{1, 3.14};
std::tie(a, std::ignore, b) = std::tuple{1, 2, 3}; // Ignore middle
// std::exchange
int x = 5;
int old = std::exchange(x, 10); // x = 10, old = 5
// std::swap
std::swap(a, b);
String Operations Quick Reference
// Construction
std::string s1 = "hello";
std::string s2(10, 'x'); // "xxxxxxxxxx"
std::string s3(s1, 1, 3); // "ell" (from pos 1, length 3)
// Concatenation
s = s1 + s2;
s = s1 + " world";
s += "!";
s.append("text");
// Substring
std::string sub = s.substr(0, 5); // From pos 0, length 5
std::string sub = s.substr(5); // From pos 5 to end
// Find
size_t pos = s.find("world"); // Returns pos or npos
size_t pos = s.find('o');
size_t pos = s.find("world", 5); // Start from pos 5
size_t pos = s.rfind("o"); // Reverse find
// Replace
s.replace(0, 5, "hi"); // Replace first 5 chars
s.replace(pos, len, "new");
// Insert/Erase
s.insert(5, "text");
s.erase(5, 4); // Erase 4 chars from pos 5
// Comparison
if (s1 == s2) {}
if (s1 < s2) {}
int cmp = s1.compare(s2); // -1, 0, or 1
// Convert
int i = std::stoi(s);
double d = std::stod(s);
long l = std::stol(s);
std::string s = std::to_string(42);
// Format (C++20)
std::string s = std::format("Hello, {}!", name);
std::string s = std::format("{0} {1} {0}", "hello", "world");
// string_view (non-owning)
std::string_view sv = s;
sv.remove_prefix(2); // Skip first 2 chars
sv.remove_suffix(2); // Skip last 2 chars
Iterator Utilities
// Advance iterator
std::advance(it, n); // Move iterator by n positions
// Distance between iterators
auto dist = std::distance(first, last);
// Next/Prev (doesn't modify original)
auto next_it = std::next(it, 3); // 3 positions ahead
auto prev_it = std::prev(it, 2); // 2 positions back
// Iterator categories
std::input_iterator_tag
std::output_iterator_tag
std::forward_iterator_tag
std::bidirectional_iterator_tag
std::random_access_iterator_tag
std::contiguous_iterator_tag // C++20
// Iterator adaptors
std::back_inserter(container); // Insert at back
std::front_inserter(container); // Insert at front
std::inserter(container, it); // Insert at position
std::reverse_iterator(it); // Reverse iteration
std::move_iterator(it); // Move elements
// Using iterator adaptors
std::copy(v1.begin(), v1.end(), std::back_inserter(v2));
Memory Management Quick Tips
// Alignment
alignas(16) int x; // Align to 16 bytes
size_t align = alignof(T); // Get alignment
// Placement new
void* mem = std::malloc(sizeof(T));
T* ptr = new (mem) T(args); // Construct at specific address
ptr->~T(); // Must manually destroy
std::free(mem);
// Allocation/Deallocation
T* ptr = new T; // ✗ Prefer smart pointers
T* arr = new T[n];
delete ptr;
delete[] arr;
// Memory operations
std::memcpy(dest, src, n); // Copy memory
std::memmove(dest, src, n); // Copy (handles overlap)
std::memset(ptr, value, n); // Set memory
std::memcmp(p1, p2, n); // Compare memory
// std::byte (C++17)
std::byte b{42};
b <<= 2;
int x = std::to_integer<int>(b);
Concurrency Quick Reference
// Thread creation
std::thread t(func, arg1, arg2);
std::thread t([](){ /* lambda */ });
t.join(); // Wait for completion
t.detach(); // Detach from thread
// jthread (C++20) - auto-joins
std::jthread t(func);
// Mutex
std::mutex mtx;
mtx.lock();
// critical section
mtx.unlock();
// Lock guards (RAII)
std::lock_guard<std::mutex> lock(mtx);
std::unique_lock<std::mutex> lock(mtx); // Can unlock before scope end
lock.unlock();
// Multiple locks
std::scoped_lock lock(mtx1, mtx2); // Deadlock-free
// Atomic
std::atomic<int> counter{0};
counter++; // Atomic increment
int val = counter.load();
counter.store(42);
int old = counter.exchange(42);
bool success = counter.compare_exchange_strong(expected, desired);
// Condition variable
std::condition_variable cv;
std::mutex mtx;
// Wait
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [&]{ return ready; });
// Notify
cv.notify_one();
cv.notify_all();
// Future/Promise
std::promise<int> prom;
std::future<int> fut = prom.get_future();
prom.set_value(42);
int result = fut.get();
// Async
auto fut = std::async(std::launch::async, func, args);
int result = fut.get();
Exception Handling
// Try-catch
try {
// code that might throw
} catch (const SpecificException& e) {
// handle specific
} catch (const std::exception& e) {
// handle standard
} catch (...) {
// handle any
}
// Throw
throw std::runtime_error("Error message");
throw std::invalid_argument("Bad argument");
throw std::out_of_range("Out of range");
// Custom exception
class MyException : public std::exception {
const char* what() const noexcept override {
return "My error";
}
};
// noexcept
void func() noexcept; // Guarantees no throw
void func() noexcept(expr); // Conditionally noexcept
// Exception safety guarantees
// 1. No-throw (noexcept)
// 2. Strong (commit or rollback)
// 3. Basic (no leaks, valid state)
// 4. No guarantee
// RAII ensures exception safety
{
std::lock_guard lock(mtx); // Released on exception
Resource r; // Cleaned up on exception
// ...
} // All cleaned up even if exception thrown
File I/O Quick Reference
// Reading file
std::ifstream file("path.txt");
if (file) {
std::string line;
while (std::getline(file, line)) {
// process line
}
}
// Writing file
std::ofstream file("path.txt");
file << "Hello, World!\n";
// Reading/Writing
std::fstream file("path.txt", std::ios::in | std::ios::out);
// Binary I/O
std::ofstream file("data.bin", std::ios::binary);
file.write(reinterpret_cast<const char*>(&data), sizeof(data));
std::ifstream file("data.bin", std::ios::binary);
file.read(reinterpret_cast<char*>(&data), sizeof(data));
// Filesystem (C++17)
namespace fs = std::filesystem;
// Check existence
if (fs::exists(path)) {}
// Create directory
fs::create_directory(path);
fs::create_directories(path); // With parents
// Remove
fs::remove(path);
fs::remove_all(path); // Recursive
// Copy
fs::copy(src, dest);
// Iterate directory
for (auto& entry : fs::directory_iterator(path)) {
std::cout << entry.path() << "\n";
}
// Recursive iteration
for (auto& entry : fs::recursive_directory_iterator(path)) {
std::cout << entry.path() << "\n";
}
// File size
size_t size = fs::file_size(path);
// Path operations
fs::path p = "/path/to/file.txt";
p.filename(); // "file.txt"
p.extension(); // ".txt"
p.stem(); // "file"
p.parent_path(); // "/path/to"
p.replace_extension(".md");
Chrono Quick Reference
// Time point
auto now = std::chrono::system_clock::now();
// Duration
std::chrono::seconds sec(60);
std::chrono::milliseconds ms(1000);
std::chrono::hours h(1);
// Duration cast
auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(sec);
// Timing
auto start = std::chrono::high_resolution_clock::now();
// ... code to measure ...
auto end = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start);
std::cout << duration.count() << " μs\n";
// Sleep
std::this_thread::sleep_for(std::chrono::seconds(1));
std::this_thread::sleep_until(time_point);
// Calendar (C++20)
auto today = std::chrono::year_month_day{std::chrono::floor<std::chrono::days>(now)};
Regex Quick Reference
#include <regex>
// Match
std::regex pattern(R"(\d+)");
if (std::regex_match(str, pattern)) {}
// Search
std::smatch matches;
if (std::regex_search(str, matches, pattern)) {
std::string match = matches[0];
}
// Replace
std::string result = std::regex_replace(str, pattern, "replacement");
// Iterator
std::sregex_iterator it(str.begin(), str.end(), pattern);
std::sregex_iterator end;
for (; it != end; ++it) {
std::cout << it->str() << "\n";
}
// Common patterns
R"(\d+)" // Digits
R"([a-zA-Z]+)" // Letters
R"(\w+)" // Word characters
R"(\s+)" // Whitespace
R"([^abc])" // Not a, b, or c
R"(^...)" // Start of string
R"(...$)" // End of string
Quick Index
Containers: vector, deque, list, array, set, map, unordered_set, unordered_map Algorithms: sort, find, copy, transform, accumulate, remove, unique Iterators: begin, end, advance, next, distance Smart Pointers: unique_ptr, shared_ptr, weak_ptr Utilities: optional, variant, any, tuple, pair Modern: ranges, concepts, coroutines, span, format Concurrency: thread, mutex, atomic, future, async Patterns: RAII, Factory, Observer, Strategy, Singleton
See Also
- OOP Concepts - Object-oriented fundamentals
- Sequence Containers - vector, list, deque
- Algorithms - Comprehensive algorithm reference
- Modern Features - C++20/23 ranges and views
- Templates - Generic programming
- Best Practices - Detailed best practices guide
- Multithreading - Concurrency in depth
Quick Reference Guide - Bookmark this page for fast lookup during development