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
0
to indicateOK/Success
- std::error_code
- used to store and transport error codes
- it has a
int
to store error code it self, andconst std::error_category*
to store theerror_category
of this error code - a
error_code
will be eitherprint
to 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_code
belongs 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_enum
template 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/NoSolution
instead of handle manyFlightsErr/SeatsErr
.
- in the flightservice example, callers only want to distinguish whether error caused by
- able to use
==/!=
to comparestd::error_code
andenum xxx
directly - able to construct
std::error_code
byenum
values (e.g.std::error_code ec = XXXEnumType::Value1
) std::error_code
only contains two members(aint
code 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_code
design 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_code
andstd::error_condition
are not the same- generally when we do
a == b
, in intuitivea
andb
have same type and same value, but they're not. - it'll very confuse if we print both
std::error_code
andstd::error_condition
into 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
0
always meansOK/Success
- use
int
to store error code - each error code has a corrsponding string message for better logging
- make error code consistent(a
int
code only has one meaning) - distinguish subsystem by use different code segment since we possible to pre-define the segments(e.g.
1000~1999
indicate A subsystem,2000~2999
indicate 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