欢迎光临散文网 会员登陆 & 注册

C++如何优雅的进行错误处理?

2023-06-02 23:43 作者:L__B_  | 我要投稿

使用expected进行错误处理

C++ 中提供了很多中方式进行错误处理。无论是通过抛异常还是通过错误码,标准库都提供相应的调用。

  1. 通过 try catch 以抛出异常的方式进行处理,这种方式很多人会觉得看起来可读性很差(包括我),并且由于缺少异常规约(某些异常必须捕获),容易出现 bug,而且异常的传递很多时候可能伴随动态分配内存,这是一笔不小的开销。

  2. 通过 error_code 作为返回值判断,这种方式虽然看似简单易用,但是由于 C++ 中并未对 error_code 作过多的规范,使用起来并不方便,很多时候还是倾向于自定义一些枚举作为自己的 error_code,但是由于缺少多返回值的语法(当然如果C++版本比较高可用使用tuple以及解构的语法实现),如果把错误码作为返回值,那么原本的数据返回就只能函数参数传递引用的形式返回了。当然,如果不考虑函数返回值的具体错误信息,可以使用 C++17 的 optional 。

由于 optional 无法包含具体的错误信息,expected 横空出世,在 C++23 开始纳入标准。如果你的C++版本较低,可以使用第三方开源的 expected 库:https://github.com/TartanLlama/expected

关于 C++23 中的新特性,包括 expected 库的使用,大家可以观看 CppCon:How C++23 Changes the Way We Write Code

下面我会以一个例子把第三方库中的 expected 库的使用方式介绍给大家。

expected 使用实例

由于该第三方库是 head-only 的,所以你只需要进到GitHub仓库把对应的头文件复制过来,便可引入使用。

下面是示例代码,样例是 cppreference 中的。

上面的代码如果想要跑通,情确保C++版本至少是C++17,因为其中用到了 string_view 以及更智能的自动类型推导(如果低于这个版本会导致unexpected需要指定明确的error类型)。

函数式的接口

  • and_then:传入一个回调,在没有错误的时候调用,该回调的返回值是新的 expected 值(可以控制err)。如果有错误返回原 expected 值。

  • or_else:传入一个回调,在有错误的时候调用,该回调的返回值是新的 expected 值(可以控制err),并且回调的参数是对应的错误类型。如果没有错误返回原 expected 值。

  • transform/map:transform 是C++23标准中规定的接口,而该第三方库作者又实现了一个名为map的接口,这两者效果是一致的。传入一个回调,在没有错误的时候调用,回调的参数和返回值都不牵扯 expected 值,只是作值的变换,所以无法控制新的 expected 的 err 值。如果有错误则返回原 expected 值。

  • transform_error/map_error:同上,但回调的调用时机和参数于 or_else 相同,但是需要注意的是,回调的返回值并不具备任何效用,也就是说如果 transform_error 中的回调被调用,那么返回的仍然是原本包含错误信息的 expected 值。

简单示例如下:


C++如何优雅的进行错误处理?的评论 (共 条)

分享到微博请遵守国家法律