Branches and loops

C++ · Essentials · 12 min

Branching and looping are the core of every algorithm, and C++ has a few forms (range-for, init-statements) that make them safer.

if (cond) { ... } else if (other) { ... } else { ... } works as in most languages. Always use braces in real code; a dangling else or an added second line under an unbraced if is a classic bug.

Since C++17, if and switch can declare a variable scoped to the statement: if (auto it = m.find(k); it != m.end()) { ... }. The variable doesn't leak into the surrounding code.

switch jumps to a matching case label on an integer, char or enum value. Execution falls through into the next case unless you break; several labels can share code deliberately, and [[fallthrough]]; marks intentional fall-through so the compiler doesn't warn. default handles everything else. You can't switch on strings.

Loops:

  • while (cond) { ... } checks before each iteration; do { ... } while (cond); runs the body at least once.
  • for (int i = 0; i < n; ++i) is the counting loop.
  • Range-based for, for (int x : v), visits every element of a container or array. Use for (const auto& x : v) to avoid copying big elements and for (auto& x : v) to modify them.

break leaves the innermost loop or switch and continue jumps to the next iteration. There's no labelled break; to exit nested loops, move them into a function and return.

Prefer range-for whenever you don't need the index; it can't go out of bounds. When you do need an index into a container, use std::size_t (or C++20 std::ssize for a signed size) to avoid signed/unsigned warnings.

Example

#include <iostream>
#include <vector>

int main() {
    std::vector<int> scores{90, 45, 72, 100, 58};

    int passed = 0;
    for (int s : scores) {                 // range-based for
        if (s < 50) continue;              // skip failures
        ++passed;
    }

    for (int i = 0; i < 3; ++i) std::cout << i << ' ';   // 0 1 2
    std::cout << '\n';

    int n = 1;
    while (n < 100) n *= 3;                // 1 3 9 27 81 243

    if (int best = scores[3]; best == 100) // C++17 if with initializer
        std::cout << "perfect score\n";

    char cmd = 'q';
    switch (cmd) {
        case 'a': std::cout << "add\n"; break;
        case 'q':
        case 'x': std::cout << "quit\n"; break;   // two labels share code
        default:  std::cout << "unknown\n";
    }
    std::cout << passed << ' ' << n << '\n';     // 4 243
}

Remember

  • Use for (const auto& x : c) to visit elements without copying
  • switch falls through without break; mark intentional cases with [[fallthrough]]
  • if (init; cond) keeps helper variables scoped to the branch

Watch out for

  • Forgetting break in a switch case, so the next case's code runs too.

Check yourself

  1. With `int x = 2;`, what does this print? `switch (x) { case 1: std::cout << 'a'; case 2: std::cout << 'b'; case 3: std::cout << 'c'; break; default: std::cout << 'd'; }`
  2. Which loop is the right choice to double every element of `std::vector<int> v` in place?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: en.cppreference.com/w/cpp/language/statements