std::expected适用于明确有限可枚举错误的场景(如文件打开、配置解析),不适用于异常不可控或需重试的场景(如http请求、regex匹配);访问前须检查状态,推荐用if(r)语法而非直接.value()。

std::expected 什么时候该用,什么时候不该用
它不是 std::optional 的替代品,也不是 throw 的平替。真正适合的场景是:函数有明确、有限、可枚举的错误类型(比如 std::errc::no_such_file_or_directory),且你不想让调用方被迫写 try/catch,也不希望用返回码 + 输出参数这种老式套路。
常见误用:包装可能抛异常的第三方库调用(比如 std::stoi)——这时候直接 try 更干净;或者把网络超时、重试逻辑塞进 std::expected —— 它不带重试语义,也不含上下文信息。
- ✅ 推荐:解析配置文件、打开已知路径的文件、读取固定格式的二进制头
- ❌ 避免:封装
std::regex_match(异常不可控)、包裹 HTTP 请求(错误种类太多,且需重试/超时)
构造和访问 std::expected 的安全方式
直接访问 .value() 或 .error() 前必须先检查状态,否则触发未定义行为(UB)。C++23 虽然加了 .value_or(),但默认值构造可能掩盖问题。
最稳妥的是用 if (auto r = parse_config(); r) { /* ok */ } else { /* handle r.error() */ } 这种模式 —— 利用 std::expected 的隐式布尔转换(operator bool()),既简洁又不会意外解包失败值。
-
r.has_value()和!r.has_value()语义等价,但前者略啰嗦 - 不要用
r.value()在未确认成功前取值,Clang/GCC 的 sanitizer 会报__builtin_unreachable -
r.value_or(T{})仅在T可默认构造且你确定兜底值有意义时才用
链式调用时如何避免嵌套 if 或手动传播 error
std::expected 没有内置 and_then(C++26 才计划加入),但可以用 lambda + transform 模拟“扁平化”流程。关键点是:每个中间步骤都返回 std::expected,失败时自动短路。
auto r1 = open_file("config.json");
if (!r1) return r1; // 直接返回 error
auto r2 = parse_json(r1.value());
if (!r2) return r2;
return validate_schema(r2.value());
上面这段可以改写为:
return open_file("config.json")
.transform([](auto&& f) { return parse_json(f); })
.transform([](auto&& j) { return validate_schema(j); });
-
.transform()只在有值时调用 lambda,失败时自动透传原 error - lambda 返回类型必须是
std::expected<u e></u>,否则编译失败(类型推导卡住) - 如果中间某步需要修改 error 类型(比如把
std::errc转成自定义ConfigError),得用.map_error()显式转换
和传统错误处理方式对比的实际代价
std::expected 是值语义,拷贝开销取决于 T 和 E 的大小。如果 T 是大对象(比如 std::vector<uint8_t></uint8_t>),而 error 很小(std::errc),那成功路径的移动构造成本比裸指针或引用返回高;但失败路径反而更轻 —— 不触发栈展开,也没有异常表开销。
- 启用
-fno-exceptions项目里,std::expected是唯一能表达“可恢复错误”的标准方案 - 和
std::result(Boost.Outcome)比,它不支持存储异常对象,也不支持延迟求值 - 注意:MSVC 2022 17.5+ 才完整支持
std::expected,GCC 13 默认开启,Clang 16 需要-std=c++23且启用libstdc++或libc++
最常被忽略的是:它的 error 类型必须满足 std::is_copy_constructible_v,不能是 move-only 类型(比如 std::unique_ptr)—— 如果真需要,得包一层或换用 std::variant<t std::unique_ptr>></t>。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











