Cheatsheet - C++

Compilation & Flags

# Compile with C++20, all warnings enabled, optimized
g++ -std=c++20 -O3 -Wall -Wextra -Wpedantic main.cpp -o main
clang++ -std=c++20 -O3 -Wall -Wextra -Wpedantic main.cpp -o main

# Debug build with AddressSanitizer and UndefinedBehaviorSanitizer
clang++ -std=c++20 -g -fsanitize=address,undefined main.cpp -o main_debug

Primitive Types & Numerics

Fixed-Width Integers (<cstdint>)

Type Bytes Range
int8_t / uint8_t 1 -128 to 127 / 0 to 255
int16_t / uint16_t 2 -32,768 to 32,767 / 0 to 65,535
int32_t / uint32_t 4 -2,147,483,648 to 2,147,483,647 / 0 to 4,294,967,295
int64_t / uint64_t 8 -9.22e18 to 9.22e18 / 0 to 1.84e19
  • Fast/Least types: std::int_fast32_t (fastest type with >=32 bits), std::int_least32_t (smallest type with >=32 bits).

Numeric Limits (<limits>)

#include <limits>

int max_int = std::numeric_limits<int>::max();
int min_int = std::numeric_limits<int>::min();       // Lowest finite for float: ::lowest()
double inf  = std::numeric_limits<double>::infinity();

Pointers, References & Operators

int x = 42;
int* p = &x;     // & = address-of, * = pointer type
*p = 100;        // * = dereference operator

int& r = x;      // & = lvalue reference (alias)
int&& rr = 42;   // && = rvalue reference (binds to temporaries or std::move)

::foo();         // Leading :: queries global scope, bypassing current namespace

Spaceship Operator (<=>, C++20)

#include <compare>

struct Point {
  int x;
  int y;
  auto operator<=>(const Point&) const = default; // Generates ==, !=, <, <=, >, >=
};

auto & Type Deduction

auto a = 5;                  // int (deduced by value; strips const and reference)
const auto& b = a;           // const int& (read-only reference, avoids copy)
auto* c = &a;                // int* (explicit pointer deduction)
auto&& d = foo();            // Forwarding / universal reference

// Structured bindings (C++17)
std::pair<int, std::string> p = {1, "alpha"};
auto [id, name] = p;

for (const auto& [key, val] : my_map) {
  std::cout << key << ": " << val << '\n';
}

Strings & String Views

#include <string>
#include <string_view>

std::string s = "Hello, C++";      // Heap-allocated, mutable string
s += "!";                          // Concatenation
s.substr(0, 5);                    // Substring copy: "Hello"
s.find("C++");                     // Returns index or std::string::npos
s.replace(0, 5, "Hi");

// std::string_view (C++17): Non-owning, read-only view (pointer + length)
std::string_view sv = s;           // Zero allocations
std::string_view sub = sv.substr(0, 2); // Zero copy

// Raw string literals
const char* raw = R"(line1\nstill raw\nline2)";

// Conversions
std::string str_num = std::to_string(42);
int num = std::stoi("42");
double dbl = std::stod("3.14");

Common Containers (<vector>, <unordered_map>, etc.)

#include <vector>
#include <unordered_map>
#include <map>

// std::vector: Contiguous dynamic array (default choice)
std::vector<int> v = {1, 2, 3};
v.push_back(4);
v.emplace_back(5);                 // In-place construction
v.size();                          // Length
v.empty();                         // Check emptiness
v.pop_back();

// std::unordered_map: Hash table (O(1) average lookup)
std::unordered_map<std::string, int> hash_map = {{"a", 1}, {"b", 2}};
hash_map["c"] = 3;
if (auto it = hash_map.find("b"); it != hash_map.end()) {
  std::cout << it->second << '\n';
}

// std::map: Red-black tree (sorted keys, O(log N) lookup)
std::map<int, std::string> sorted_map;
sorted_map[2] = "two";

Control Flow & Loops

// if with initializer (C++17)
if (auto it = hash_map.find("key"); it != hash_map.end()) {
  use(it->second);
}

// Range-based for loops
for (const auto& item : v) { /* read only */ }
for (auto& item : v)       { item *= 2; /* mutate in-place */ }

// Traditional loop
for (size_t i = 0; i < v.size(); ++i) { /* index loop */ }

// Switch statement
switch (val) {
  case 1:  do_one(); break;
  case 2:  do_two(); break;
  default: do_fallback(); break;
}

Lambdas (C++11/14/20)

#include <algorithm>

// [capture](parameters) -> return_type { body }
auto add = [](int a, int b) { return a + b; };

// Captures:
// [ ]        Capture nothing
// [&]        Capture all automatic variables by reference
// [=]        Capture all automatic variables by copy
// [this]     Capture current object pointer
// [&x, y]    Capture x by reference, y by copy

std::vector<int> nums = {4, 1, 8, 3};
std::sort(nums.begin(), nums.end(), [](int a, int b) {
  return a > b; // Descending
});

Smart Pointers (<memory>)

#include <memory>

// std::unique_ptr: Exclusive ownership (zero overhead, cannot copy, can move)
auto u = std::make_unique<int>(42);
std::unique_ptr<int> u2 = std::move(u); // u becomes null

// std::shared_ptr: Shared ownership via atomic reference count
auto s1 = std::make_shared<std::string>("shared data");
auto s2 = s1;                           // Reference count increments

// std::weak_ptr: Non-owning observer to break cyclical references
std::weak_ptr<std::string> w = s1;
if (auto locked = w.lock()) {           // Returns shared_ptr if alive
  std::cout << *locked << '\n';
}

Classes, Structs & Object Lifecycle

class Widget {
 public:
  Widget() = default;                               // Default constructor
  explicit Widget(int val) : val_(val) {}           // Prevent implicit conversion
  ~Widget() = default;                              // Destructor

  // Rule of 5 for resource ownership:
  Widget(const Widget&) = default;                  // Copy constructor
  Widget& operator=(const Widget&) = default;       // Copy assignment
  Widget(Widget&&) noexcept = default;              // Move constructor
  Widget& operator=(Widget&&) noexcept = default;   // Move assignment

  int value() const { return val_; }                // Const member function
  void set_value(int val) { val_ = val; }

 private:
  int val_ = 0;
};

// Scoped enum (enum class)
enum class Status : uint8_t {
  kPending = 0,
  kSuccess,
  kFailed,
};

Type Casting

// static_cast: Compile-time conversion (numeric conversions, upcasts)
double d = 3.14;
int i = static_cast<int>(d);

// dynamic_cast: Runtime checked downcast for polymorphic types (returns nullptr / throws)
Base* base = new Derived();
Derived* derived = dynamic_cast<Derived*>(base);

// const_cast: Add or remove const qualification
const int ci = 10;
int* modifiable = const_cast<int*>(&ci);

// reinterpret_cast: Low-level bit reinterpretation
uintptr_t addr = reinterpret_cast<uintptr_t>(base);