Google C++每周贴士 #76: 使用absl::Status

本文介绍了Google的C++编程建议,强调使用absl::Status作为错误处理手段,强制调用者处理错误并允许在上下文丰富的层级进行错误处理。absl::Status不是异常,而是通过显式处理确保错误不会被忽略,提高了代码的可读性和错误处理的效率。
摘要由CSDN通过智能技术生成

(原文链接:https://abseil.io/tips/76 译者:clangpp@gmail.com)

每周贴士 #76: 使用absl::Status

有同学提问在什么时候、该怎么使用absl::Status,所以这里准备了一些应该使用Status的情况,以及使用的时候要注意些什么。

传达意图且强制调用者处理错误

使用Status来强制调用者处理可能出现的错误。从2013年6月开始,作为函数返回值的Status对象不能被忽略。换句话说,如下的代码会得到编译错误:

absl::Status Foo();

void CallFoo1() {
  Foo();
}

然而以下这些调用没毛病:

void CallFoo2() {
  Foo().IgnoreError();
}

void CallFoo3() {
  if (!status.ok()) std::abort();
}

void CallFoo4() {
  absl::Status status = Foo();
  if (!status.ok()) std::cerr << status;
}

既然我们费了半天劲让编译器确保Status不能被忽略,为什么Status还可以有成员函数IgnoreError()?设想你是代码审查员,正在审查CallFoo1()CallFoo2()。代码审查员看到后者后会思考“这个函数可能返回错误,但是代码作者认为可以忽略它。对不对?”CallFoo1()不会引发这样的思考。

允许调用者在上下文更丰富的地方处理错误

在你的代码不清楚该如何处理错误的时候,返回Status,让拥有更多上下文的调用者来处理这个错误。

例如,在本地打印日志可能会影响效率,比如在写基础框架代码的时候。如果你的代码在紧凑循环中被调用,就算调用std::cout也许都会太贵。其他情况下,用户也许根本不在乎某一次调用是否成功,但会被垃圾日志烦死。

很多情况下打印日志是合理的,但是返回Status的函数不需要通过LOG来解释为什么执行失败:它们可以返回错误代码和错误信息,让调用者决定如何正确地处理错误。

这不就是重新发明异常吗?

Google编程规范(出了名地)禁用了异常(关于这一点的讨论比其他任何禁用特性都要多)。人们很容易认为absl::Status是“土法炼钢”(poor-man)的异常机制,且附带很多额外开销。但除了表面看起来像,absl::Status区别于异常在于,它必须被显式处理,而不是作为未处理异常一路退栈到底。它强制工程师决定如何处理错误,然后显式地以可编译代码的形式说明之。最后,以absl::Status返回错误,要比抛出(throw)和接受(catch)异常的执行速度快几个数量级。这些特性在写代码的时候有点烦人,但每个读代码的人都是纯赚,Google整体也因此得益。

结论

错误处理是做容易搞砸的事情之一:它们天然是边缘情况。如Status这样的工具增加了跨API边界、跨项目、跨进程以及跨语言的错误处理一致性,帮助我们最小化了诸如“我们的错误处理有问题”这样的坑。如果你在设计一个需要表达失败可能性的接口,且没有特别强烈的原因选择其他方案,请考虑使用Status

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值