std::error_code比throw更轻量,适合高频预期错误;它是值类型、零开销、无RTTI/堆分配、支持多错误域和跨平台语义归一,需谨慎设计error_category边界。
当错误是预期中频繁发生的(比如网络超时、文件不存在、系统调用返回 EAGAIN),用 throw 会触发栈展开,开销大且不可预测。而 std::error_code 是值类型,仅含两个整数字段:value() 和 category(),构造/拷贝零成本,无异常机制的运行时负担。
errno、WSAGetLastError())天然对齐,转换无损传统 errno 是全局变量,多次系统调用可能覆盖前一次错误;std::error_code 把错误值和其语义绑定在同一个对象里,靠 std::error_category 区分来源。例如:
std::error_code ec1 = std::make_error_code(std::errc::no_such_file_or_directory); // generic_category std::error_code ec2 = std::error_code(WSAENOTCONN, system_category()); // Windows 网络错误 ec1.category() != ec2.category(); // true
ry 控制 message()、default_error_condition() 等行为std::error_category 实现自定义错误域(如数据库错误、协议解析错误)ec1 == ec2 为 false,即使 value() 相同)std::error_code 描述“发生了什么”,std::error_condition 描述“意味着什么”。比如 EPERM(Linux)、ACCESS_DENIED(Windows)、SEC_E_ACCESS_DENIED(SSPI)都映射到同一个 std::errc::permission_denied 条件。
std::error_condition 分支,而非原始 error_code.value()
category::default_error_condition() 实现跨平台语义归一if (ec.value() == 13) 这类不可移植代码std::error_code 支持隐式构造(如 return std::errc::invalid_argument;),但容易掩盖错误未检查问题。更安全的做法是:
std::error_code& 引用参数(推荐)std::expected(C++23)std::error_code 并删掉 explicit 构造函数(需谨慎)-Wimplicit-exception-spec-mismatch(Clang)或类似警告真正难的是设计 error category 的边界——比如把 HTTP 状态码塞进 system_category 还是另建 category,这决定了错误能否被上层统一处理。没想清楚这点,后面所有优化都只是搬砖。