Step 1 of 7
Bugs vs expected failures
Every real program meets failure. The first skill is telling apart two very different kinds:
- 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.
- 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
- Asserts are for programmer mistakes. Never use them to check user input: a user typing a bad value shouldn't crash the program.
- Release builds often define
NDEBUG, which removes everyassert. So never put code with side effects inside one: inassert(save_file() == 0), the file would never be saved in a release build. Call the function first, then assert on its result.
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 turn: add an assert that n is positive. With a valid call the program prints ok.