We can't find the internet
Attempting to reconnect
Something went wrong!
Attempting to reconnect
← Errors step 4 of 4
The handler that hid the failure
There are three honest answers to “this can go wrong”, and the skill is telling which one you are looking at.
| The situation | The answer |
|---|---|
| An outcome the caller should expect and act on |
Return it. std::optional, an error enum, std::expected in C++23. |
| A failure the caller cannot prevent and may want to recover from | Throw it. The disk, the network, an allocation. |
| A broken assumption inside your own program |
Refuse to continue. assert, or terminate. |
The third row surprises people, so it is worth being blunt about. If a function’s precondition is violated — a null pointer where the contract said non-null, an index the caller was told to bound, an invariant that cannot be true — then your program has a bug, and it is now operating on state nobody designed for. Continuing means computing a wrong answer and writing it somewhere. Stopping means a stack trace and a fix.
assert(index < size_); // a claim about the program, removed by NDEBUG
if (!file) throw IoError{...}; // a claim about the world, always checked
assert is for things you believe cannot happen. Exceptions are for things
you know can.
Which brings us to catch (...)
try {
everything();
} catch (...) {
return 0;
}
This is the shape that turns a bug into a wrong number. It catches the failure you anticipated, and also the null dereference, the failed allocation, the invariant violation and the exception a colleague added last month — and reports all of them as a plausible-looking zero, at a call site with no idea anything happened.
Two rules follow, and they are the whole lesson:
Catch the specific types you know how to handle. If you cannot say what you would do about it, you cannot handle it, and catching it only hides it from someone who could.
Scope the
tryto the smallest thing that can fail. Atryaround a whole loop cannot resume; atryaround one iteration can.
catch (...) has exactly one legitimate use: logging at a boundary and then
throw; to rethrow. It is never a recovery.
Your task
std::vector<long long> tally(const std::vector<std::string>& fields);
Each field should be an integer. Return two numbers: the sum of the ones that parse, and how many did not.
std::stoll throws std::invalid_argument when the text is not a number,
and std::out_of_range when it will not fit. Those are the two you know how
to handle: skip the field and count it.
The starter wraps the whole loop and answers every failure with a zero, so one bad field discards every good one before it.
Stuck?
C++ reference solution
Sign in to attempt this problem and reveal the reference solution.