【发布时间】:2020-04-24 19:24:33
【问题描述】:
假设我有一个函数(为简单起见,请忽略它不是异步的)
http_response http_get(string url, std::error_code& ec);
当这个函数失败时,它通过ec返回一个错误。到目前为止一切顺利。
现在,假设我有另一个函数多次使用http_get:
int calculate_meaning_of_life(std::error_code& ec) {
auto r1 = http_get("foo.com", ec);
if (ec) return 0;
auto r2 = http_get("bar.com", ec);
if (ec) return 0;
return combine(r1, r2);
}
但是现在我有一个问题,当calculate_meaning_of_life 函数失败时,我丢失了关于它是对http_get 的哪个调用的信息。
另一种方法可能是我定义自定义错误代码,并像这样使用它们:
int calculate_meaning_of_life(std::error_code& ec) {
std::error_code internal_ec;
auto r1 = http_get("foo.com", internal_ec);
if (internal_ec) {
ec = custom_error::failed_at_foo_com;
return 0;
}
auto r2 = http_get("bar.com", internal_ec);
if (internal_ec) {
ec = custom_error::failed_at_bar_com;
return 0;
}
return combine(r1, r2);
}
但现在我丢失了有关 http_get 内部发生的事情的信息。理想情况下,我想保留所有信息,如下所示:
int calculate_meaning_of_life(std::error_code& ec) {
std::error_code internal_ec;
auto r1 = http_get("foo.com", internal_ec);
if (internal_ec) {
ec = meaning_error(custom_error::failed_at_foo_com, internal_ec);
return 0;
}
auto r2 = http_get("bar.com", internal_ec);
if (internal_ec) {
ec = meaning_error(custom_error::failed_at_bar_com, internal_ec);
return 0;
}
return combine(r1, r2);
}
因此,当我运行它但它失败时,我可以获得所有可用信息。例如:
std::cerr << ec << "\n"; // Would print: "Failed to retrieve foo.com: operation aborted"
据我了解,std::error_code 只是一个int 和一个指向类别结构的指针,所以我认为没有一种非骇客的方法可以使std::error_code 中的int 实际上代表一个结构。
我现在能想到的制作这种复合错误代码的唯一“hackish”方法是滥用int 来实际表示多个值。例如。通过为自定义错误代码“保留”前 K 位并为“内部”错误代码保留,或者使用 Cantor's pairing function 或类似的东西。
所以最后的问题是:有没有推荐的方法来构造这样的复合错误代码?和/或在 WWW 的某个地方是否有关于此类复合错误代码的讨论?或者也许有其他选择?
【问题讨论】:
-
如果错误是“异常的”,那么是否会抛出异常?
-
谢谢,尽管它们通常不是“异常”,这是我目前感兴趣的情况。在我们的代码库中,我们不使用异常也是这种情况,因为与Boost.Asio 和协程他们搞砸了地址清理器(至少在 g++ 上)。
-
@PeterJankuliak 通常错误代码不被认为是很好的解决方案 AFAIK。处理异常情况有两种很好但不同的策略 - 异常和“结果类型”,它是返回类型和错误消息/错误对象的变体。两者都支持您的需求。如果这些情况不是例外,我建议只检查和
ifs,这意味着这是预期的行为 -
@PeterJankuliak 如果我理解正确,您想在编写错误时尽可能多地保留有关发生错误的上下文和错误本身的信息吗?
-
@GauravDhiman 是的,没错
标签: c++ error-code