Custom Exception Types
intermediate20 min readLesson 118 of 204
Deriving from std::runtime_error, carrying structured data, and designing the type around the handler's decision.
When what() strings are not enough structure, define exception types.
Derive from std::runtime_error (or logic_error) and carry the data
the handler needs:
#include <stdexcept>
#include <string>
class ValidationError : public std::runtime_error {
public:
ValidationError(std::string field, std::string message)
: std::runtime_error{field + ": " + message},
field_{std::move(field)}, message_{std::move(message)} {}
const std::string& field() const noexcept { return field_; }
private:
std::string field_;
std::string message_;
};
Rules that keep custom exceptions safe:
- constructor must not throw (it would abort during unwinding);
what()is satisfied for free bystd::runtime_error;- copy members exist by default — exceptions are copied as they unwind, so members must be copyable;
- catch handlers get
const ValidationError&and can read.field()without parsing strings.
Design the type around the handler's decision: what would a caller do
differently for this failure than for any other? If the answer is
"nothing", a plain std::runtime_error string was enough.