我目前正在构建一个嵌入式系统并使用现代 C++ 编译器。
虽然我在技术上可以在给定资源(ARM7,超过 10M RAM)中进行异常处理,但我认为异常不是处理此类事情的正确工具,并且使用异常需要 RTTI,这反过来会导致代码膨胀。
无论如何,为了保持 C++ 风格,我想使用 std::error_code
(或类似的更多数据)因为我确实喜欢这个概念。
但是,对于如何实际使用它们似乎没有任何共识。我已经看到至少四种在函数调用之间传递它们的不同方式,其中两种具有多种语义。
void somefunction(Args..., std::error_code* error);
这是我不经常看到的方式,也是我最不喜欢的方式。它使返回类型完全可用并且(通常但不总是)通过 nullptr
导致正常的 throw 行为。void somefunction(Args..., std::error_code& error);
这是我更喜欢的一个。它离开 returnvalue
完全可用,并明确指出 error_code
不是可选的。std::error_code somefunction(Ret& out <= if used, Args...);
我经常看到这个,但不是很喜欢它,因为它会耗尽你的返回值,而且我通常不喜欢“输出参数”,除非没有办法绕过它们。std::variant<Ret, std::error_code>
std::variant<Ret, std::error_code> somefunction(Args...);
这允许返回值,但使访问值和错误更加困难。此外,它使调用函数的代码更加冗长。语义
如果
error_code
,我已经看到具有不同语义的方式1和2已通过。error_code
则在开始时立即返回是“设置”如果您想减少调用代码中的错误检查,最后一种方法非常好。因为你可以通过一个
error_code
多个函数之间没有检查,并且第一个错误之后的所有内容都不会执行,类似于异常的执行方式。我个人确实更喜欢检查和返回的方式2,但是我可能有偏见。
有一些推荐/普遍接受的方法吗?
最佳答案
好的,这不是完整的答案,实际上也不是完美的主题,因为我不知道执行此操作的标准方法。但是我曾经看到一个漂亮的小技巧,可以让错误代码更难被误用。考虑以下代码:
结构 MyEC {
我的EC(){}
我的EC(我的EC &&其他): parent (&其他){
//如果未检查其他,则可能记录和或中止
其他.checked = false;
}
//删除其他构造函数和赋值运算符
〜我的EC(){
if(!checked && parent == nullptr) {
//记录和或中止
}
}
[[nodiscard]] std::error_code check() {
检查=真;
返回 ec;
}
无效集(std::error_code err){
如果(父 == nullptr) ec = err;
否则 parent ->设置(错误);
}
私有(private)的:
MyEC* 父级 = nullptr;
检查=真;
std::error_code ec {};
};
int foo(MyEC&& err) {
err.set(/* 一些错误 */);
返回 5;
}
int foo1(MyEC&&) {
返回 4;
}
无效酒吧(){
MyEC 错误;
富(标准::移动(错误));
//err 有错误代码,如果没有检查,我们会知道
foo1(std::move(err));
//即使没有发生错误,如果没有检查错误,我们也会中止。
}
当错误代码未设置但也未检查时,它甚至会中止,这非常好。移动后有很多用处,有点奇怪,不过这里没问题。
关于c++ - 使用 `std::error_code` 的最佳实践,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62611885/