I am currently building an embedded system and use a modern C++ compiler.\nWhile I could technically fit exception handling in the given resources (ARM7, more than 10M RAM), I don\xe2\x80\x99t think exceptions are the right tool for something like this and using exceptions requires RTTI, which in turn results in code bloat.
\nTo 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.
\nPassing by pointer as an argument
\nvoid somefunction(Args..., std::error_code* error);\nRun Code Online (Sandbox Code Playgroud)\nThis 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
\nvoid somefunction(Args..., std::error_code& error);\nRun Code Online (Sandbox Code Playgroud)\nThis is the one I prefer. It leaves returnvalue fully available and makes clear that the error_code is not optional.
Returning it by value
\nstd::error_code somefunction(Ret& out <= if used, Args...);\nRun Code Online (Sandbox Code Playgroud)\nI have seen this one quite often but don\xe2\x80\x99t really like it that much, as it uses up your return value and I generally don\xe2\x80\x99t like \xe2\x80\x9cout parameters\xe2\x80\x9d unless there\xe2\x80\x99s no way around them.
\nReturning a std::variant<Ret, std::error_code>
std::variant<Ret, std::error_code> somefunction(Args...);\nRun Code Online (Sandbox Code Playgroud)\nThis one allows for a return value, but makes accessing both value and error harder. Also, it makes code calling the function more verbose.
\nI have seen both way 1 and 2 with different semantics, if the error_code is passed.
error_code is \xe2\x80\x9cset\xe2\x80\x9dThe 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.
\nIs there some recommended / generally accepted way to do it?
\n好吧,这不是完整的答案,实际上并不完全符合主题,因为我不知道执行此操作的标准方法。但我曾经看到过一个巧妙的小技巧,可以使错误代码更难被滥用。考虑以下代码:
结构MyEC {
MyEC() {}
MyEC(MyEC && 其他) : 父级(&其他) {
// 如果没有检查其他,可能会记录和/或中止
其他.检查=假;
}
// 删除其他构造函数和赋值运算符
~MyEC() {
if(!checked && 父 == nullptr) {
// 记录和/或中止
}
}
[[nodiscard]] std::error_code check() {
检查=真;
返回EC;
}
无效集(std::error_code err){
if(父== nullptr) ec = err;
否则父->设置(错误);
}
私人的:
MyEC* 父级 = nullptr;
检查=真;
std::error_code ec {};
};
int foo(MyEC&& 错误) {
err.set(/* 一些错误 */);
返回5;
}
int foo1(MyEC&&) {
返回4;
}
无效栏(){
MyEC 错误;
foo(std::move(err));
// err 有错误代码,如果不检查,我们就会知道
foo1(std::move(err));
// 即使没有发生错误,如果没有检查 err,我们也会中止。
}
当错误代码未设置但也未检查时,它甚至会中止,这非常好。move之后还有很多用处,有点奇怪,不过这里没有问题。
| 归档时间: |
|
| 查看次数: |
2359 次 |
| 最近记录: |