Understanding standard library error code and try its usage, i.e. std::error_code, std::error_category, std::error_condition.
It's a flight service comes from Your own error code, see my implementation in flightservice.
-
requirements for the flight service
- It's used for looking for flight connections. You tell me where from and where to you want to go, and I will offer you concrete flights, and a price.
- In order to be able to do this, the flight service calls other services in turn:
- one for finding the (short) sequence of flights that will take you to your destination,
- one for checking if there is still seats available on these flights in the requested class of service (economy class, business class),
- Each of these services can fail for a number of reasons.
- See details in Your own error code.
-
coding style
$ cd flightservice
$ clang-format -style=webkit -i *- run test
$ cd flightservice
$ g++ -std=c++14 main.cpp flights_err.cpp seats_err.cpp failure_source.cpp && ./a.out
FlightsErr:10
value: 10 msg: nonexistent airport name in request
FailureSource message: invalid user request
SeatsErr:20
value: 20 msg: all seats booked
FailureSource message: no solution found for specified request
- always use
0to indicateOK/Success
- std::error_code
- used to store and transport error codes
- it has a
intto store error code it self, andconst std::error_category*to store theerror_categoryof this error code - a
error_codewill be eitherprintto log or compare witherror_condition
- std::error_category
- used to store which subsystem the error comes from, and give concrete message of each code value of the subsystem
- when call
error_code.message(), the concrete message will be returned due to its polymorphic properties
- std::error_condition
- used to match errors
- callers will only handle errors by check whether
error_codebelongs toerror_condition(the meaning is 'belongs to' though using==)
See example in flightservice.
- define your own error code/condition enum, e.g.
enum class xxx - specialize the
std::is_error_code_enum/is_error_condition_enumtemplate for your error code/condition enum - overload the
make_error_code()/make_error_condition()function for your error code/condition enum - implement your error category(inherit from
std::error_category) for your error code/condition enum(so that it's possible to print subsystem name and concrete message into log)
-
Pros
- able to store error code itself in a
int - able to distinguish which subsystem the error comes from
- able to print concrete code value and message to log
- callers only need to handle errors they care (
std::error_condition)- in the flightservice example, callers only want to distinguish whether error caused by
BadUserInput/InternalError/NoSolutioninstead of handle manyFlightsErr/SeatsErr.
- in the flightservice example, callers only want to distinguish whether error caused by
- able to use
==/!=to comparestd::error_codeandenum xxxdirectly - able to construct
std::error_codebyenumvalues (e.g.std::error_code ec = XXXEnumType::Value1) std::error_codeonly contains two members(aintcode and aconst std::category*), lightweight
- able to store error code itself in a
-
Cons
- difficult to understand
- i.e. difficult to understand the whole story that why design it like this(maybe due to too complex requirements of standard library)
- difficult to use
- e.g. library/application developers have to do a lot of work to plugin new defined enum to
std::error_code - e.g. users have to understand the
std::error_codedesign before use it
- e.g. library/application developers have to do a lot of work to plugin new defined enum to
- values of
std::error_codeandstd::error_conditionare not the same- generally when we do
a == b, in intuitiveaandbhave same type and same value, but they're not. - it'll very confuse if we print both
std::error_codeandstd::error_conditioninto log.
- generally when we do
- difficult to understand
std::error_code is designed for C++ standard library, which may have a lot of complex requirments to make it so complex like this.
When we need a error code design for our own library/application, there could be some ideas can help us to get a simpler but sufficient design.
- follow the convention that
0always meansOK/Success - use
intto store error code - each error code has a corrsponding string message for better logging
- make error code consistent(a
intcode only has one meaning) - distinguish subsystem by use different code segment since we possible to pre-define the segments(e.g.
1000~1999indicate A subsystem,2000~2999indicate B subsystem, etc.) - simplify error handling for caller
- provide methods for caller maybe a good way, e.g. rocksdb/status.h, leveldb/status.h
- you can teach a new error condition to recognize existing error codes, but also you can teach a new error code to be recognized by existing error conditions
It's metioned in Your own error condition. Not quite understand it.
- Your own error code
- Your own error condition
- Use cases for std::error_code
- std::error_code
- std::error_category
- std::error_condition
- System error support in C++0x - part 1
- System error support in C++0x - part 2
- System error support in C++0x - part 3
- System error support in C++0x - part 4
- System error support in C++0x - part 5
- rocksdb/status.h
- leveldb/status.h