1. std::expected 基础概念与常见误解
在 C++23 中引入的 std::expected 是一个模板类,用于表示可能成功或失败的操作结果。它的基本形式是 std::expected<T, E>,其中 T 是期望的成功结果类型,E 是错误类型。很多人对这个新特性存在严重误解,特别是在文件操作场景下。
1.1 std::expected 的本质
std::expected 本质上是一个包含两种可能状态的联合体:
- 包含期望的值(成功情况)
- 包含错误信息(失败情况)
它并不是异常机制的替代品,而是一种更明确、更可控的错误处理方式。与异常相比,std::expected 的优势在于:
- 错误处理路径在编译期就可见
- 不会引入额外的运行时开销
- 强制调用者处理可能的错误情况
1.2 常见误解剖析
最常见的误解是认为 std::expected 会自动将抛出异常的函数转换为返回 std::expected 的函数。这种想法是完全错误的。标准库中的文件操作函数(如 std::fstream 构造函数或 std::filesystem::open)仍然会抛出异常,不会自动返回 std::expected。
另一个常见误区是认为 std::expected 会捕获所有可能的异常。实际上,如果不手动封装,std::filesystem::file_error 等异常仍然会直接抛出并可能导致程序崩溃。
2. 文件操作的手动封装实践
要在文件操作中使用 std::expected,必须手动封装可能抛出异常的操作。下面详细介绍如何正确实现这种封装。
2.1 基本封装模式
最基本的封装模式是创建一个函数,它尝试执行文件操作,捕获可能抛出的异常,并返回 std::expected。以下是一个典型的结构:
cpp复制#include <expected>
#include <fstream>
#include <filesystem>
#include <string>
std::expected<std::fstream, std::string> open_file(const std::filesystem::path& path) {
try {
std::fstr
