C++ Cheatsheet for Experienced Developers
Memory Management & RAII
Smart Pointers
// Unique ownership
auto p1 = std::make_unique<T>(args);
auto p2 = std::unique_ptr<T>(new T(args));
// Shared ownership
auto sp = std::make_shared<T>(args);
auto wp = std::weak_ptr<T>(sp); // Non-owning
// Using weak_ptr
if (auto locked = wp.lock()) {
// Use locked as shared_ptr
}
// Custom deleters
auto del = [](T\* p) {
// Custom cleanup logic
delete p;
};
std::unique_ptr<T, decltype(del)> p(new T(), del);Resource Management
// RAII pattern
class Resource {
private:
FILE* handle;
public:
Resource(const char* filename)
: handle(fopen(filename, "r")) {
if (!handle)
throw std::runtime_error("File error");
}
~Resource() {
if (handle) fclose(handle);
}
// Prevent copying
Resource(const Resource&) = delete;
Resource& operator=(const Resource&) = delete;
// Allow moving
Resource(Resource&& other) noexcept
: handle(other.handle) {
other.handle = nullptr;
}
Resource& operator=(Resource&& other) noexcept {
if (this != &other) {
if (handle) fclose(handle);
handle = other.handle;
other.handle = nullptr;
}
return *this;
}
};Templates & Metaprogramming
SFINAE & Type Traits
// SFINAE pattern
template <typename T,
typename = std::enable*if_t<
std::is_integral_v<T>>>
void func(T value) { /*...\_/ }
// Concepts (C++20)
template <std::integral T>
void func(T value) { /_..._/ }
// Type traits
static_assert(std::is_same_v<T, U>);
if constexpr (std::is_arithmetic_v<T>) {
// For arithmetic types
} else {
// For other types
}Variadic Templates
// Recursive variadic templates
template<typename T>
void print(const T& t) {
std::cout << t << '\n';
}
template<typename T, typename... Args>
void print(const T& t, const Args&... args) {
std::cout << t << ' ';
print(args...);
}
// Fold expressions (C++17)
template<typename... Args>
auto sum(Args... args) {
return (args + ...); // Unary right fold
}Modern C++ Features
Move Semantics
// Perfect forwarding
template<typename T, typename... Args>
std::unique_ptr<T> make(Args>>... args) {
return std::unique_ptr<T>(
new T(std::forward<Args>(args)...));
}
// Move operations
class Widget {
std::vector<int> data;
public:
// Move constructor
Widget(Widget&& other) noexcept
: data(std::move(other.data)) {}
// Move assignment
Widget& operator=(Widget&& other) noexcept {
if (this != &other)
data = std::move(other.data);
return *this;
}
};Lambdas & Closures
// Basic lambda
auto add = [](int a, int b) { return a + b; };
// Lambda with capture
int multiplier = 5;
auto times = [multiplier](int x) {
return x \* multiplier;
};
// Mutable lambda
auto counter = [count = 0]() mutable {
return ++count;
};
// Generic lambda (C++14)
auto generic = [](auto x, auto y) { return x + y; };
// Lambda with explicit return type
auto divide = [](double a, double b) -> double {
return a / b;
};
// Capture with initialization (C++14)
auto func = [ptr = std::make_unique<int>(42)]() {
return \*ptr;
};Structured Bindings (C++17)
// With array
int arr[3] = {1, 2, 3};
auto [a, b, c] = arr;
// With tuple
auto [name, age] = std::make_tuple("Alice", 30);
// With pair (common in map operations)
auto [iter, success] = myMap.insert({key, value});
// With struct
struct Point { int x, y; };
Point p{1, 2};
auto [px, py] = p;Range-Based For Loop
// Basic usage
for (const auto& item : container) { /_..._/ }
// With structured bindings (C++17)
for (const auto& [key, value] : map) { /_..._/ }
// With initialization (C++20)
for (std::vector v{1,2,3}; auto& elem : v) {
/_..._/
}STL & Algorithms
Algorithm Patterns
// Finding elements
auto it = std::find_if(begin(c), end(c),
[](const auto& x) { return x > 10; });
// Transforming elements
std::transform(begin(src), end(src), begin(dest),
[](const auto& x) { return x \* 2; });
// Functional operations
auto sum = std::accumulate(begin(c), end(c), 0);
auto product = std::accumulate(begin(c), end(c), 1,
std::multiplies<>());
// Removing elements (erase-remove idiom)
// Note: remove_if doesn't change container size
auto new_end = std::remove_if(begin(v), end(v),
[](int x) { return x % 2 == 0; });
v.erase(new_end, end(v));
// Sorting with custom comparator
std::sort(begin(v), end(v),
[](const auto& a, const auto& b) {
return a.priority > b.priority;
});Containers & Iterators
// Container adaptors
std::priority_queue<T, std::vector<T>, Compare> pq;
std::stack<T> stack;
std::queue<T> queue;
// Using iterators
auto it = container.begin();
std::advance(it, 5); // Move forward by 5
auto dist = std::distance(container.begin(), it);
// Iterator adapters
auto rbegin = container.rbegin(); // Reverse
std::back_inserter(container); // Insert at end
// C++20 ranges
auto view = std::ranges::views::filter(
container, [](const auto& x) {
return x > 0;
});Concurrency
// Thread creation
std::thread t([](int x) {
/_ thread work _/
}, 42);
t.join(); // Wait for thread completion
// Mutex and lock
std::mutex mtx;
{
std::lock_guard<std::mutex> lock(mtx);
// Critical section
}
// More flexible locking
std::unique_lock<std::mutex> lock(mtx,
std::defer_lock); // Don't lock yet
// ... some code ...
lock.lock(); // Now lock
// Condition variable
std::condition_variable cv;
cv.wait(lock, []{ return ready; });
cv.notify_one(); // Wake one waiting threadClasses & OOP
Special Member Functions
class MyClass {
public:
// Constructor
MyClass() = default;
// Custom constructor (explicit prevents implicit)
explicit MyClass(int val) : value(val) {}
// Destructor
~MyClass() = default;
// Copy operations
MyClass(const MyClass&) = delete; // No copying
MyClass& operator=(const MyClass&) = delete;
// Move operations
MyClass(MyClass&&) noexcept = default;
MyClass& operator=(MyClass&&) noexcept = default;
private:
int value = 0;
};Inheritance Patterns
// Abstract base class
class Shape {
public:
virtual ~Shape() = default; // Virtual destructor
virtual double area() const = 0; // Pure virtual
virtual void draw() const {
// Default implementation
}
};
// CRTP pattern (static polymorphism)
template<typename Derived>
class Base {
public:
void interface() {
static_cast<Derived*>(this)->implementation();
}
protected:
// Default implementation if needed
void implementation() { /* default \*/ }
};Type Deduction
// auto vs decltype
auto x = expr; // Type from initialization
decltype(expr) y; // Type of expr (no evaluation)
// Function return type deduction (C++14)
auto func() { return value; }
// Trailing return type
auto func() -> decltype(expr) { return expr; }
// decltype(auto) (C++14)
decltype(auto) f() { return (x); } // Returns ref
// Forwarding references
template<typename T>
void f(T&& param); // Universal/forwarding refCommon Patterns & Idioms
// Const-correctness
void func(const T& arg) const noexcept;
// Rule of zero/five
// Either:
// 1. Define no special members (zero)
// or
// 2. Define all five: destructor, copy ctor,
// copy assign, move ctor, move assign
// Prevent narrowing conversions
T x{narrower}; // Error if narrowing occurs
// Make non-copyable but movable
X(const X&) = delete;
X& operator=(const X&) = delete;
X(X&&) = default;
X& operator=(X&&) = default;
// Virtual inheritance (diamond problem)
class B : public virtual A { /_..._/ };
// const member function overloading
T& operator[](size_t idx);
const T& operator[](size_t idx) const;