I am currently building an embedded system and use a modern C++ compiler. While I could technically fit exception handling in the given resources (ARM7, more than 10M RAM), I don’t think exceptions are the right tool for something like this and using exceptions requires RTTI, which in turn results in code bloat.
To stay C++-ish anyway I want to use std::error_code (or similar with more data) because I do like the concept.
However, there does not seem to be any consenus on how to actually use them. I have seen at least four different ways of passing them between function calls, two of them with multiple semantics.
Passing by pointer as an argument
void somefunction(Args..., std::error_code* error);This is the way I have not seen that often and the one I dislike the most. It leaves the return type fully available and (often, but not always) passing
nullptrresulted in normal throwing behaviour.Passing by reference as an argument
void somefunction(Args..., std::error_code& error);This is the one I prefer. It leaves
returnvaluefully available and makes clear that theerror_codeis not optional.Returning it by value
std::error_code somefunction(Ret& out <= if used, Args...);I have seen this one quite often but don’t really like it that much, as it uses up your return value and I generally don’t like “out parameters” unless there’s no way around them.
Returning a
std::variant<Ret, std::error_code>std::variant<Ret, std::error_code> somefunction(Args...);This one allows for a return value, but makes accessing both value and error harder. Also, it makes code calling the function more verbose.
Semantics
I have seen both way 1 and 2 with different semantics, if the error_code is passed.
- Clear at start and set on error
- Only set on error
- Return right at start if the
error_codeis “set”
The last way is pretty good if you want to reduce error checking in the calling code. As you can just pass one error_code to multiple functions without checking in between and everything after the first error will not execute, similar to how exceptions would do it.
I personally do prefer way 2 with checking and returning, however I might be biased.
Is there some recommended / generally accepted way to do it?