C++ Cheatsheet

Control Flow

Use this C++ reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

if / else

if (x > 0) {
    // ...
} else if (x < 0) {
    // ...
} else {
    // ...
}

// Single-statement (braces optional but recommended)
if (x > 0) doSomething();

// if with initializer (C++17)
if (int n = compute(); n > 0) {
    use(n);         // n is in scope here and in else
} else {
    handle(n);
}

// Constexpr if — branch chosen at compile time (C++17)
template<typename T>
void process(T val) {
    if constexpr (std::is_integral_v<T>) {
        // only compiled when T is integral
    } else {
        // only compiled otherwise
    }
}

switch

switch (expr) {         // expr must be integral or enum
    case 1:
        doA();
        break;          // without break, falls through to next case
    case 2:
    case 3:             // multiple cases share one body
        doBC();
        break;
    case 4:
        doD();
        [[fallthrough]]; // C++17: explicit intentional fallthrough (silences warning)
    case 5:
        doDE();
        break;
    default:
        doDefault();
        break;          // good practice even in default
}

// switch with initializer (C++17)
switch (auto ch = getChar(); ch) {
    case 'a': /* ... */ break;
    default:  /* ... */
}

Variables cannot be declared between cases without a block:

case 2: {
    int x = 5;   // OK inside a block
    break;
}

while Loop

while (condition) {
    // body — runs as long as condition is true
    // condition checked BEFORE each iteration
}

int i = 0;
while (i < 10) {
    std::cout << i << " ";
    ++i;
}

// Infinite loop
while (true) {
    if (done) break;
}

do-while Loop

do {
    // body always runs at least once
    // condition checked AFTER each iteration
} while (condition);

int choice;
do {
    std::cout << "Enter 1-3: ";
    std::cin >> choice;
} while (choice < 1 || choice > 3);

for Loop

// Classic for
for (init; condition; increment) { body }

for (int i = 0; i < n; ++i) { /* i = 0, 1, ..., n-1 */ }
for (int i = n - 1; i >= 0; --i) { /* reverse */ }
for (int i = 0, j = n - 1; i < j; ++i, --j) { /* two vars */ }

// Infinite loop
for (;;) { if (done) break; }

// Range-based for (C++11)
std::vector<int> v = {1, 2, 3};
for (int x : v) { /* copy */ }
for (int& x : v) { x *= 2; /* modify in place */ }
for (const int& x : v) { /* read-only, no copy */ }
for (auto x : v) { /* deduce type */ }
for (auto [key, val] : myMap) { /* structured binding, C++17 */ }

// Range-based for with initializer (C++20)
for (auto&& v = getVec(); auto x : v) { use(x); }  // auto&& binds the rvalue

break, continue, goto

// break — exit the innermost loop or switch
for (int i = 0; i < 10; ++i) {
    if (i == 5) break;  // stops at 5
}

// continue — skip the rest of the current iteration
for (int i = 0; i < 10; ++i) {
    if (i % 2 == 0) continue;  // skip even
    process(i);
}

// goto — jump to label (avoid; useful only for breaking nested loops)
for (int i = 0; i < 10; ++i) {
    for (int j = 0; j < 10; ++j) {
        if (bad(i, j)) goto done;
    }
}
done:
// continues here

Ternary Operator

int abs_x = (x >= 0) ? x : -x;

// Chained (readable only for two levels)
std::string grade = (score >= 90) ? "A"
                  : (score >= 80) ? "B"
                  : (score >= 70) ? "C"
                  :                 "F";

// Can be used where a value is required (unlike if)
std::cout << (x > 0 ? "positive" : "non-positive") << "\n";

std::optional as a Control Flow Tool (C++17)

#include <optional>

std::optional<int> find(int key) {
    if (/* found */) return 42;
    return std::nullopt;
}

if (auto result = find(key)) {
    use(*result);          // dereference
}

Structured Bindings (C++17)

#include <tuple>
#include <map>

auto [a, b] = std::pair{1, 2.0};       // a=int, b=double
auto [x, y, z] = std::tuple{1, 2, 3};

std::map<std::string, int> m = {{"a", 1}};
for (auto& [key, val] : m) {
    std::cout << key << "=" << val << "\n";
}

// Ignoring elements (no official discard, use _)
auto [first, _] = std::pair{1, 99};   // some compilers warn on duplicate _

Early Return Pattern

// Prefer returning early over deep nesting
int process(int x) {
    if (x < 0) return -1;       // guard clause
    if (x == 0) return 0;
    return x * 2;
}

Loops Over Containers — Patterns

#include <vector>
#include <algorithm>

std::vector<int> v = {3, 1, 4, 1, 5};

// Index-based (when index matters)
for (std::size_t i = 0; i < v.size(); ++i) { v[i] *= 2; }

// Iterator-based
for (auto it = v.begin(); it != v.end(); ++it) { *it *= 2; }

// Range-for (preferred)
for (auto& x : v) { x *= 2; }

// Algorithm (see STL Algorithms)
std::for_each(v.begin(), v.end(), [](int& x){ x *= 2; });

Jump Table Alternative with Arrays

// Replace long switch on sequential ints with a function table
using Fn = void(*)();
Fn table[] = { funcA, funcB, funcC };
if (cmd < 3) table[cmd]();

Assertions

#include <cassert>

assert(x > 0);            // aborts if false in debug builds
                          // disabled when NDEBUG is defined (release builds)

// C++11: static_assert (compile-time)
static_assert(sizeof(int) == 4, "Expected 32-bit int");
static_assert(std::is_trivial_v<MyStruct>);  // no message required (C++17)