0

0

C++中如何利用std::expected优雅地替代异常处理?(C++23代码流控制)

穿越時空

穿越時空

发布时间:2026-03-14 18:59:03

|

577人浏览过

|

来源于php中文网

原创

std::expected 不能替代 try/catch,它仅替代错误码+手动检查;不触发栈展开,显式返回成功值或错误对象,适用于预期会失败的场景(如I/O、解析),而非真正意外错误。

c++中如何利用std::expected优雅地替代异常处理?(c++23代码流控制)

std::expected 不能替代 try/catch,它只替代「返回错误码 + 手动检查」

很多人以为 std::expected 是异常的“平替”,其实不是:它不触发栈展开,不改变控制流,也不捕获异常。它的定位是让函数**显式返回成功值或错误对象**,把错误处理从隐式(抛异常)变成显式(检查 has_value() 或用 and_then 链式传递)。适合 I/O、解析、配置加载等「预期会失败」的场景,而不是空指针解引用这类真正意外的错误。

常见错误现象:std::expected<int std::string> f() { throw std::runtime_error("oops"); }</int> —— 这不会自动转成 std::unexpected,而是直接崩溃。必须手动构造 std::unexpected 或用 return std::unexpected("oops")

  • 函数签名要提前决定是否用 std::expected:一旦返回 std::expected,调用方就必须处理两种状态,没法“假装没看见错误”
  • 错误类型必须可复制/可移动,且不能是 voidstd::expected<void e></void> 合法,但 std::expected<t void></t> 不合法
  • std::optional 不同,std::expected 的错误分支是第一类公民,不是“缺省值”的补丁

用 and_then 和 or_else 实现零开销链式错误传播

and_then 只在有值时调用回调,回调必须返回另一个 std::expectedor_else 只在出错时调用,用于错误恢复或转换。它们不分配内存,也不抛异常,纯函数式风格。

使用场景:读文件 → 解析 JSON → 提取字段。每一步都可能失败,但你不想写三层 if (!res.has_value()) return res;

立即学习C++免费学习笔记(深入)”;

示例:

AssemblyAI
AssemblyAI

转录和理解语音的AI模型

下载
auto load_config = [](std::string_view path) -> std::expected<std::string, std::string> {
  std::ifstream f(path.data());
  if (!f.is_open()) return std::unexpected("open failed");
  return std::string{std::istreambuf_iterator(f), {}};
};

auto parse_json = [](std::string s) -> std::expected<nlohmann::json, std::string> {
  try { return nlohmann::json::parse(s); }
  catch (const nlohmann::json::exception& e) { return std::unexpected(e.what()); }
};

auto get_port = [](nlohmann::json j) -> std::expected<int, std::string> {
  if (j.contains("port") && j["port"].is_number_integer())
    return j["port"].get<int>();
  return std::unexpected("missing or invalid port");
};

auto port = load_config("/etc/app.json")
  .and_then(parse_json)
  .and_then(get_port);
  • and_then 回调里如果抛异常,程序直接终止——它不捕获,所以务必确保回调自身不抛
  • or_else 返回 std::expected 才能继续链式调用;若只想记录日志并转成新错误,得写 return std::unexpected(new_msg)
  • 编译器对链式调用优化很好,但嵌套过深(>5 层)可能影响调试体验——错误位置指向最后一层,而非源头

和传统错误码对比:别忽略移动语义和值类别陷阱

int 错误码 + errno 风格,容易误读成功值为错误码(比如返回 -1 表示 EOF,但业务逻辑也用 -1 表示未设置)。std::expected 强制区分,但代价是:每次移动都涉及判别字段(has_value_)和对齐填充,比裸 int 大 2–4 字节。

性能影响:小对象(如 std::expected<int std::error_code></int>)通常内联无开销;大错误类型(如含堆内存的 std::string)要注意避免不必要的拷贝。

  • 别直接 return e.value()std::expected 中取值——先用 e.has_value()e.value_or(0),否则触发 std::terminate
  • e.value() 是左值,e.value_or(x) 返回右值;若 T 移动代价高,优先用 std::move(e).value() 避免二次拷贝
  • 兼容性注意:MSVC 19.35+、GCC 12.2+、Clang 16+ 才完整支持 C++23 的 std::expected;旧版本需用 absl::StatusOrtl::expected 替代

什么时候不该用 std::expected?

当错误发生意味着程序处于不可恢复的非法状态时,比如内存耗尽、硬件故障、断言失败——这些该用异常或 std::terminate,而不是塞进 std::expected 里假装还能“继续执行”。还有就是高频小函数(如数学库的 sqrt),加一层 std::expected 会破坏内联和向量化。

最容易被忽略的一点:std::expected 的错误类型必须明确表达“为什么失败”,而不是笼统的 int。用 std::error_codeint 好,但自定义枚举(如 enum class parse_err { missing_comma, invalid_number })配合 std::expected<t parse_err></t>,才能让调用方做精确分支处理,而不是靠字符串匹配。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
json数据格式
json数据格式

JSON是一种轻量级的数据交换格式。本专题为大家带来json数据格式相关文章,帮助大家解决问题。

457

2023.08.07

json是什么
json是什么

JSON是一种轻量级的数据交换格式,具有简洁、易读、跨平台和语言的特点,JSON数据是通过键值对的方式进行组织,其中键是字符串,值可以是字符串、数值、布尔值、数组、对象或者null,在Web开发、数据交换和配置文件等方面得到广泛应用。本专题为大家提供json相关的文章、下载、课程内容,供大家免费下载体验。

549

2023.08.23

jquery怎么操作json
jquery怎么操作json

操作的方法有:1、“$.parseJSON(jsonString)”2、“$.getJSON(url, data, success)”;3、“$.each(obj, callback)”;4、“$.ajax()”。更多jquery怎么操作json的详细内容,可以访问本专题下面的文章。

337

2023.10.13

go语言处理json数据方法
go语言处理json数据方法

本专题整合了go语言中处理json数据方法,阅读专题下面的文章了解更多详细内容。

82

2025.09.10

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

1051

2023.08.02

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

847

2023.08.22

js 字符串转数组
js 字符串转数组

js字符串转数组的方法:1、使用“split()”方法;2、使用“Array.from()”方法;3、使用for循环遍历;4、使用“Array.split()”方法。本专题为大家提供js字符串转数组的相关的文章、下载、课程内容,供大家免费下载体验。

761

2023.08.03

js截取字符串的方法
js截取字符串的方法

js截取字符串的方法有substring()方法、substr()方法、slice()方法、split()方法和slice()方法。本专题为大家提供字符串相关的文章、下载、课程内容,供大家免费下载体验。

221

2023.09.04

TypeScript类型系统进阶与大型前端项目实践
TypeScript类型系统进阶与大型前端项目实践

本专题围绕 TypeScript 在大型前端项目中的应用展开,深入讲解类型系统设计与工程化开发方法。内容包括泛型与高级类型、类型推断机制、声明文件编写、模块化结构设计以及代码规范管理。通过真实项目案例分析,帮助开发者构建类型安全、结构清晰、易维护的前端工程体系,提高团队协作效率与代码质量。

49

2026.03.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
C# 教程
C# 教程

共94课时 | 11.3万人学习

C 教程
C 教程

共75课时 | 5.4万人学习

C++教程
C++教程

共115课时 | 21.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号