Step 2 of 7
Status codes
The oldest approach, straight from C: the function returns a status (did it work?), and delivers the actual result through a reference parameter.
#include <iostream>
#include <string>
[[nodiscard]] bool withdraw(int& balance, int amount) {
if (amount <= 0 || amount > balance) return false; // refuse, change nothing
balance -= amount;
return true;
}
int main() {
int balance = 100;
for (int amount : {30, 500, -5, 70}) {
if (withdraw(balance, amount)) {
std::cout << "took " << amount << ", left " << balance << "\n";
} else {
std::cout << "refused " << amount << "\n";
}
}
// withdraw(balance, 10); // warning: ignoring return value declared with 'nodiscard'
}
took 30, left 70
refused 500
refused -5
took 70, left 0
How it works
- The return value answers "did it work?". The real output (the new balance here) goes through the
int¶meter. - On failure, the function changes nothing. Callers can rely on that: a failed withdrawal leaves the balance intact.
[[nodiscard]]makes the compiler warn if a caller ignores the result. Without it,withdraw(balance, 500);would silently fail, and the caller would carry on believing the money was taken.
Strengths and weaknesses
It's simple, fast and works everywhere, including C. But the caller must remember to check, the result has to be declared before the call, and a plain bool can't say why it failed. The next steps improve on each of those.
Your task
Division by zero is the failure case: return false and leave out alone. Otherwise store a / b in out and return true. Add [[nodiscard]] before the return type.
Your turn: write [[nodiscard]] bool divide(int a, int b, int& out) that returns false for division by zero and otherwise stores a / b in out.
Previous: Bugs vs expected failures Next: optional for "maybe"