当前位置: 首页 > news >正文

std::expected

std::expected是 C++23 标准库引入的一个类模板,用于表示一个操作可能成功并返回一个值,也可能失败并返回一个错误信息。它提供了一种类型安全、语义明确且零成本的现代错误处理机制,旨在替代传统的错误码和异常。

🤔 为什么需要 std::expected?

std::expected出现之前,C++ 的错误处理方式各有痛点:

  • 错误码 (Error Codes):容易被调用者忽略,且无法携带丰富的错误上下文信息。
  • 异常 (Exceptions):虽然能携带详细信息,但存在性能开销(栈展开),并且会使控制流变得隐式和难以追踪。在一些对性能敏感或禁用异常的环境中(如游戏引擎、嵌入式系统)不适用。
  • std::optional<T>:只能表示“有值”或“无值”,但无法说明“为什么无值”。

std::expected<T, E>完美地解决了这些问题。它明确表示一个操作要么返回一个类型为T的成功值,要么返回一个类型为E的错误值。这迫使调用者必须显式地处理失败的情况,从而提高了代码的健壮性。

💡 基本用法

std::expected的使用非常直观。

#include <expected> #include <iostream> #include <string> // 一个可能失败的函数:除法运算 std::expected<double, std::string> divide(double a, double b) { if (b == 0.0) { // 返回一个错误 return std::unexpected("除数不能为零"); } // 返回成功值 return a / b; } int main() { auto result = divide(10.0, 2.0); // 1. 检查是否包含有效值 if (result.has_value()) { // 2. 获取成功值 std::cout << "结果: " << result.value() << std::endl; } else { // 3. 获取错误信息 std::cout << "错误: " << result.error() << std::endl; } // 更简洁的布尔检查 auto bad_result = divide(5.0, 0.0); if (bad_result) { std::cout << "结果: " << *bad_result << std::endl; // 解引用操作符 } else { std::cout << "错误: " << bad_result.error() << std::endl; } return 0; }

✨ 核心优势:函数式组合

std::expected最强大的地方在于它支持链式调用,可以将多个可能失败的操作优雅地组合在一起,避免深层的if-else嵌套。

  • and_then:如果当前expected对象包含值,则调用提供的函数(该函数也必须返回一个std::expected);如果当前是错误,则直接短路,传递错误。
  • or_else:如果当前expected对象包含错误,则调用提供的函数进行错误恢复或转换。
  • transform:如果当前包含值,则对值进行转换。
// 假设我们有以下几个可能失败的函数 std::expected<std::string, std::error_code> read_file(const std::string& path); std::expected<Config, std::error_code> parse_json(const std::string& json); std::expected<void, std::error_code> validate_config(const Config& cfg); // 使用 and_then 进行链式调用 auto config_result = read_file("config.json") .and_then(parse_json) .and_then(validate_config); if (!config_result) { // 任何一步失败,都会到达这里 std::cerr << "配置加载失败: " << config_result.error().message() << std::endl; }

📊 与其他机制的对比

特性std::expected<T, E>std::optional<T>异常 (throw/catch)
核心语义成功(T) 或 失败(E)有值 或 无值正常流 或 意外中断
错误信息携带具体错误对象 (E)携带异常对象
性能零成本,无栈展开零成本有开销(栈展开)
控制流显式,编译器强制检查显式隐式,难以追踪

✅ 何时使用?

std::expected适用于处理那些可预期的、常规的、可恢复的错误。

  • I/O 操作:文件不存在、网络超时、权限不足。
  • 数据解析:JSON 格式错误、字符串转换数字失败。
  • 业务逻辑校验:用户输入不符合规则。

不应该用它来处理程序逻辑缺陷或资源耗尽等意外的、不可恢复的灾难性错误(如内存分配失败std::bad_alloc、数组越界),这些情况仍然应该交给异常或std::abort处理。

http://www.jsqmd.com/news/542857/

相关文章:

  • Windows触控体验的革命:ThreeFingerDragOnWindows如何重新定义三指拖拽
  • 裂隙注浆模拟:当岩层遇上高粘度浆液
  • Llama-3.2V-11B-cot实操手册:上传JPG/PNG后实时视觉推理全流程
  • LVGL字体扩展避坑指南:freetype缓存管理导致的内存泄漏问题排查实录
  • 基于ViT模型的移动端图像分类应用开发
  • 从VS Code到CLion:跨IDE统一CMake构建命令的最佳实践(含--config参数详解)
  • VMware Unlocker终极指南:如何在Windows和Linux上高效运行macOS虚拟机
  • 第4章 编码规范-4.2 注释规范
  • Qwen3-ASR-0.6B WebUI实战:中文方言自动识别与结果导出操作
  • YOLO-v8.3问题解决:常见报错与GPU配置避坑指南
  • Sonic数字人效果展示:看静态图片如何“开口说话”生成流畅视频
  • 【三维模型+视频】COMSOL 6.2-三维超声辅助激光熔覆案例。 介绍:对于激光熔覆,激光束...
  • 你的CDD文件真的‘干净’吗?深度解析CANoe.Diva自动化测试背后的诊断数据库质量门禁
  • STEP3-VL-10B多场景落地:跨境电商Listing图合规检测(Logo/文字)
  • 节能模式:OpenClaw+nanobot的间歇性任务调度技巧
  • AutoGen Studio作品分享:基于低代码平台构建的智能体团队实战
  • Ubuntu 20.04下rMATS 4.1.2环境配置避坑指南(含GSL 2.5依赖解决方案)
  • Python无GIL时代来了?揭秘CPython 3.13+无锁并发模型的8个高频面试陷阱
  • 为什么你的模型训练慢3.7倍?——深度解析NumPy/PyTorch/JAX张量底层布局差异与迁移避坑清单
  • 告别调试靠猜!用华大单片机串口高效打印调试信息(基于UART0和可变参数函数)
  • c++ 右值引用
  • translategemma-27b-it部署指南:Ollama模型缓存管理与多版本切换实践
  • Onekey终极指南:3分钟快速获取Steam游戏清单的完整解决方案
  • 分享一份2026金三银四Java面试通关宝典!
  • 3大维度解放双手:March7thAssistant让星穹铁道自动化更智能
  • Qwen3-ASR-1.7B司法存证应用:庭审录音自动转写+时间轴对齐(联动aligner)
  • HunyuanVideo-Foley效果展示:雨声/脚步声/玻璃碎裂等高频细节还原对比
  • 【AI应用开发】-Agent 思考时间那么长,怎么优化前端的用户体验?
  • HJ148 迷宫寻路
  • LFM2.5-1.2B-Thinking应用实战:用Ollama搭建一个能“思考”的智能问答助手