Error handling in C and C++
Return codes, errno, exceptions, std::optional and std::expected, and how to choose between them.
There are several ways to report that something failed:
- Return codes (C style): return -1 or
NULLand seterrno. Simple, but easy to ignore. - Exceptions (
throw/try/catch): errors can't be silently ignored, and RAII cleans up as the stack unwinds. Standard C++ uses them for truly exceptional failures. std::optional<T>: "a value or nothing", when the reason doesn't matter.std::expected<T, E>(C++23): a value or an error explaining why.
Whatever you pick, be consistent within a codebase, and never let a failure pass silently.
Example
#include <charconv>
#include <iostream>
#include <optional>
#include <string_view>
std::optional<int> parse_int(std::string_view s) {
int value = 0;
auto [end, ec] = std::from_chars(s.data(), s.data() + s.size(), value);
if (ec != std::errc() || end != s.data() + s.size()) return std::nullopt;
return value;
}
int main() {
std::cout << parse_int("42").value_or(-1) << " " << parse_int("4x2").has_value() << "\n";
return 0;
}
Output:
42 0