我目前正在构建一个嵌入式系统,并使用现代C++编译器。虽然从技术上讲,我可以在给定的资源(ARM7,超过10M RAM)中适配异常处理,但我认为异常不是这种情况下的合适工具,并且使用异常需要RTTI,这反过来会导致代码膨胀。
为了保持C++风格,我想要使用std::error_code
(或类似带有更多数据的内容),因为我喜欢这个概念。
但是,似乎没有任何共识可以告诉我如何实际使用它们。我至少看到了四种不同的在函数调用之间传递它们的方法,其中两种具有多个语义。
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
nullptr
resulted 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
returnvalue
fully available and makes clear that theerror_code
is 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.
语义学
我看到了两种不同的语义方式,如果传递了error_code
参数:
- 在开始时清除并在出现错误时设置
- 仅在出现错误时设置
- 如果
error_code
被“设置”,则立即返回正确值
如果您想减少调用代码中的错误检查,则最后一种方法非常好。因为您可以只传递一个error_code
参数给多个函数,而无需在它们之间进行检查;在出现第一个错误后,其余的所有内容都将不会执行,类似于异常处理。
我个人更喜欢第二种带检查和返回的方式,但我可能有偏见。
是否有一些建议或通常接受的做法呢?
std::runtime_error
并捕获const std::exception&
。编译器(或者准确来说是异常实现)需要一种方法来确定它们是否匹配,使用 rtti(类似于 dynamic_cast 的方式)。你可以禁用 rtti 并使用异常,但这只会禁用前端,实际的 rtti 信息和后端函数仍然会被发出。 - Thalhammer