c++如何利用C++23的std::expected重构传统的文件IO报错代码【进阶】

千丽小哥_2951

千丽小哥_2951

2026-03-31

711人浏览

原创

c++oding="utf-8" ?>

std::expected 是为“值或错误详情”建模而生,典型场景是替代传统文件io中丢弃失败原因的做法;它强制处理成功与失败分支,错误类型e推荐用std::error_code以支持跨平台错误分类与比对。

c++如何利用c++23的std::expected重构传统的文件io报错代码【进阶】

std::expected 替代 std::optional + 异常或返回码的典型场景

传统 C++ 文件 IO 常用 std::ifstream 的 is_open() 或 fail() 判断,再配合手动设错误码、抛异常,或者用 std::optional<:string></:string> 表示“读成功”,但完全丢弃了失败原因。这导致调用方无法区分是“文件不存在”还是“权限不足”或“磁盘满”。std::expected<t e></t> 正是为这种“值 or 错误详情”建模而生——它强制你处理两种分支,且错误类型 E 可以是 std::error_code,天然对接系统级错误。

实操建议:

  • std::expected<:string std::error_code></:string> 是最常用组合:成功时带内容,失败时带 POSIX 错误码(如 EACCES、ENOENT)
  • 别用 std::expected<t std::string></t> ——字符串无法参与 switch、不好比对、丢失错误分类语义
  • 构造失败态时,优先用 std::unexpect 包装 std::error_code(errno, std::generic_category()),而非裸传整数

用 std::expected 封装 std::filesystem::read_file(C++23)

C++23 标准库终于有了 std::filesystem::read_file,但它不返回 std::expected,而是直接抛异常。要获得预期行为,必须自己封装一层。

实操建议:

  • 捕获 std::filesystem::filesystem_error,从中提取 .code()(即 std::error_code),再用 std::unexpected 构造失败返回
  • 不要忽略 .path1() 和 .path2() ——它们在调试时能快速定位是哪个路径出问题,可存入自定义错误结构体(若需更丰富上下文)
  • 若目标是零异常二进制(如嵌入式或游戏热更新),必须用 open() + read() 系统调用重写底层,再转成 std::expected;标准 read_file 本质仍依赖异常传播

示例片段:

C++ Code Review Master
C++ Code Review Master

组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。

下载
std::expected<:vector>, std::error_code> safe_read_binary(const std::filesystem::path& p) {
    try {
        return std::filesystem::read_file(p);
    } catch (const std::filesystem::filesystem_error& e) {
        return std::unexpected(e.code());
    }
}</:vector>

链式调用中 and_then 与错误透传的陷阱

很多人想用 and_then 把“读文件 → 解析 JSON → 验证字段”串起来,但容易踩两个坑:一是 and_then 的 lambda 返回类型必须严格匹配外层 std::expected 的 value 类型,二是错误类型不兼容时编译失败,而非静默吞掉错误。

实操建议:

  • 所有中间步骤的返回类型统一用 std::expected<t std::error_code></t>,避免混用 std::errc、int 或自定义枚举(除非显式特化 std::is_error_code_enum)
  • 若某步可能产生新错误类型(如 JSON 解析失败应返回 json_parse_error),要么将其映射到 std::errc 子集(如 std::errc::invalid_argument),要么把整个链的错误类型升级为 std::variant<:error_code json_error></:error_code>
  • transform 比 and_then 更安全:它只处理 success 分支,失败态自动透传,适合纯数据转换(如 std::vector<:byte></:byte> → std::string)

Windows 下 std::error_code 与 Win32 错误码的兼容性细节

在 Windows 上,std::filesystem 内部用 Win32 API(如 CreateFileW),其错误码(如 ERROR_FILE_NOT_FOUND)会被自动转为 std::error_code,但类别是 std::system_category(),不是 std::generic_category()。这意味着直接比对 std::errc::no_such_file_or_directory 会失败。

实操建议:

  • 用 ec.default_error_condition() 转换后再比对: ec.default_error_condition() == std::errc::no_such_file_or_directory
  • 跨平台代码中,永远别假设 std::error_code 的值等于某个 errno 数字;只依赖 default_error_condition() 或 category() + value() 组合判断
  • MinGW 和 MSVC 对此处理一致,但某些旧版 libc++ 可能未完全实现 default_error_condition 映射,CI 中务必覆盖 Windows + libc++ 测试

事情说清了就结束。真正麻烦的从来不是怎么写 std::expected,而是决定哪些错误值得暴露、哪些该被上游吞掉、以及错误码语义在不同系统间是否真的一致。

C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!

相关文章

c++速学教程(入门到精通)
c++速学教程(入门到精通)

c++怎么学习?c++怎么入门?c++在哪学?c++怎么学才快?不用担心,这里为大家提供了c++速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

c++

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

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

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

2023.08.07

1995

5

json是什么
json是什么

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

2023.08.23

2782

1

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

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

2023.10.13

956

3

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

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

2025.09.10

3119

7

string转int
string转int

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

2023.08.02

5419

3

switch语句用法
switch语句用法

switch语句用法:1、Switch语句只能用于整数类型,枚举类型和String类型,不能用于浮点数类型和布尔类型;2、每个case语句后面必须跟着一个break语句,以防止执行其他case的代码块,没有break语句,将会继续执行下一个case的代码块;3、可以在一个case语句中匹配多个值,使用逗号分隔;4、Switch语句中的default代码块是可选的等等。

2023.09.21

1031

6

Java switch的用法
Java switch的用法

Java中的switch语句用于根据不同的条件执行不同的代码块。想了解更多switch的相关内容,可以阅读本专题下面的文章。

2024.03.13

1377

13

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

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

2023.08.03

1578

5

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

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

2023.09.04

2324

5

热门下载

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

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Conan 2 Essentials 免费课程
Conan 2 Essentials 免费课程

共0课时 | 0人学习

CMake 与 Conan 集成实践
CMake 与 Conan 集成实践

共0课时 | 0人学习

Conan 2 高级依赖模型介绍
Conan 2 高级依赖模型介绍

共0课时 | 0人学习