C/C++ Arena

Step 1 of 7

Bugs vs expected failures

Every real program meets failure. The first skill is telling apart two very different kinds:

  1. Bugs: a broken assumption in your own code. A function that requires a positive size gets a negative one; an index that "can't" be out of range is. Nothing sensible can happen next, and the fix is to change the code.
  2. Expected failures: things that go wrong in normal use. The user types letters where a number goes, a file is missing, a player isn't found. These aren't bugs, so the program must handle them and keep going.

assert: tripwires for bugs

assert(condition) from <cassert> checks something that must always be true. If it's false, the program stops immediately and prints the file, line and condition that failed, which points you straight at the bug.

#include <cassert>
#include <iostream>
#include <vector>

int middle(const std::vector<int>& sorted) {
    assert(!sorted.empty());          // callers must never pass an empty vector
    return sorted[sorted.size() / 2];
}

int main() {
    std::cout << middle({1, 3, 7, 9, 12}) << "\n";
    std::cout << middle({4}) << "\n";
    // middle({});  would stop the program with something like:
    //   main.cpp:6: int middle(...): Assertion `!sorted.empty()' failed.
}
7
4

Exceptions, and when code avoids them

Exceptions (throw/try/catch) are standard C++'s general tool for failure: a throw unwinds the stack to the nearest matching catch, running destructors on the way (RAII again!).

try {
    int x = std::stoi("abc");   // throws std::invalid_argument
} catch (const std::exception& e) {
    std::cout << e.what();
}

Exceptions work in this site's compiler, and the exceptions step later in this module has you throw and catch them. But many real codebases turn them off (-fno-exceptions) or avoid them by policy: games, embedded systems and some large companies (Google's C++ style guide, for example, doesn't use them), usually for predictable performance or binary size. So the next steps first cover the exception-free patterns they use: status codes, std::optional and a Result type. Knowing both styles, and when each fits, is what professionals need.

Your task

Add an assert that n is positive. With a valid call the program prints ok.

Challenge 2

static_assert checks at compile time and assert checks while the program runs. Complete both: the build must refuse machines with ints smaller than 4 bytes, and at must catch an index outside the vector. The program prints 15.

Challenge 3

A handy trick: assert(cond && "message"). The string is always true, so it doesn't change the check, but it shows up in the failure report. Add the precondition that whole is positive, and the postcondition that the result is at most 100. The program prints 75.

Next: Status codes