使用expected进行错误处理
这篇文章围绕 C++ 错误处理演进,重点说明了为什么在“需要返回错误细节”时应优先考虑 expected。背景与动机文章先对比了异常机制与错误码返回两类常见方案。异常路径在可读性、规约统一性和潜在性能开销上存在现实争议。传统错误码方式在多返回值表达和规范一致性上也有痛点。optional 与 expected 的边界o…
使用expected进行错误处理 C++ 中提供了很多中方式进行错误处理。无论是通过抛异常还是通过错误码,标准库都提供相应的调用。通过 try catch 以抛出异常的方式进行处理,这种方式很多人会觉得看起来可读性很差(包括我),并且由于缺少异常规约(某些异常必须捕获),容易出现 bug,而且异常的传递很多时候可能伴随动态分配内存,这是一笔不小的开销。通过 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 中的。#include "expected.h" #include <iomanip> #include <iostream> #include <string> enum class parse_error { invalid_input, overflow }; tl::expected<double, parse_error> parse_number(std::string_view& str) { const char* begin = str.data(); char* end; double retval = std::strtod(begin, &end); if (begin == end) return tl::unexpected(parse_error::invalid_input); else if (std::isinf(retval)) return tl::unexpected(parse_error::overflow); str.remove_prefix(end - begin); return retval; } int main() { auto process = [](std::string_view str) { std::cout << "str: " << std::quoted(str) << ", "; if (const auto num = parse_number(str); num) { std::cout << "value: " << *num << '\n'; // If num did not have a value, dereferencing num // would cause an undefined behavior, and // num.value() would throw std::bad_expected_access. // num.value_or(123) uses specified default value 123. } else if (num.error() == parse_error::invalid_input) { std::cout << "error: invalid input\n"; } else if (num.error() == parse_error::overflow) { std::cout << "error: overflow\n"; } else { std::cout << "unexpected!\n";// or invoke std::unreachable(); } }; for (auto src : {"42", "42abc", "meow", "inf"}) process(src); } 上面的代码如果想要跑通,情确保C++版本至少是C++17,因为其中用到了 stri…
正在初始化 WebAssembly 引擎…
首次编译原生模块可能需要数秒
就绪后,页面交互将以接近原生的速度运行