Error Handling¶
C++ offers exceptions, return values, optional/expected-like values, error codes, termination, and assertions. Choose according to whether failure is recoverable, expected, local, and representable in the type contract.
Exceptions¶
Exceptions separate the normal return path from failure propagation and interact with RAII so constructed local objects are destroyed during stack unwinding.
percentage parse_percentage(std::string_view text) {
double value{};
auto const [end, error] = std::from_chars(
text.data(), text.data() + text.size(), value);
if (error != std::errc{} || end != text.data() + text.size()) {
throw std::invalid_argument{"invalid percentage"};
}
return percentage{value};
}
Catch polymorphic exceptions by reference to avoid slicing:
Catch only where the program can recover, translate at an abstraction boundary, or add necessary context. Repeatedly logging and rethrowing creates duplicate noise.
Exception guarantees¶
- no-throw: the operation does not emit exceptions;
- strong: failure has no observable effect on the operation's target state;
- basic: invariants hold and resources do not leak, but state may change;
- no guarantee: even invariants may not be preserved.
Document the relevant guarantee. RAII is the foundation, but a strong guarantee may require compute-then-commit, copy-and-swap, or transactional structure.
noexcept¶
noexcept is a promise: if an exception escapes such a function, the program
terminates. Use it for operations that truly cannot fail by exception, especially
destructors and truthful move operations. Do not add it merely to silence analysis.
Values for expected absence or failure¶
std::optional<T>represents a value that may be absent without explaining why;std::expected<T, E>(standardized in C++23) represents a value or typed error;std::error_coderepresents non-throwing error categories and values;- a domain result type can carry richer application-specific failure.
Do not use an exception for ordinary loop termination or a Boolean when callers need to distinguish failure causes.
Assertions and contracts¶
Assertions diagnose violated programmer assumptions in applicable builds. They must not perform required side effects and are not input validation for untrusted data. Public precondition policy should be consistent and documented.
Exercises¶
- Choose an error representation for “key absent,” malformed input, and disk failure.
- Give a strong-guarantee implementation strategy for replacing a collection.
- Explain why throwing from a destructor during unwinding is dangerous.