C++打造自己的std::error_code 目录1.std::error_category详解2.自定义 error_category2.1.实现步骤2.2.完整代码2.3.error_code、error_condition、error_category 三者关系2.4.常见误区2.5.关键要点总结1.std::error_category详解std::error_category定义于system_error头文件是 C11 引入的错误类别抽象基类用于区分不同来源的错误系统 errno、自定义错误、IO 错误等。每个错误类别拥有唯一名称std::error_code、std::error_condition依靠它识别错误类型。#include system_error类声明namespace std { class error_category { public: // 禁止拷贝 error_category(const error_category) delete; error_category operator(const error_category) delete; // 虚析构 virtual ~error_category() noexcept; // 纯虚函数子类必须实现 virtual const char* name() const noexcept 0; virtual std::string message(int ev) const 0; // 可选重写比较error_code与error_condition virtual bool equivalent(const std::error_code code, int condition) const noexcept; // 获取类别全局唯一对象 static const error_category system_category() noexcept; static const error_category generic_category() noexcept; }; }核心成员函数解析1析构函数virtual ~error_category() noexcept虚析构保证派生类可以正确析构。2virtual const char* name() const noexcept 0【必须重写】返回错误类别的名字例如系统类别返回system自定义类别返回自定义字符串用于标识错误来源。3virtual std::string message(int ev) const 0【必须重写】输入错误码数值ev返回该错误对应的人类可读的文字描述错误信息由该方法生成。4equivalent虚函数判断一个error_code是否匹配某个错误条件默认实现一般不需要改动。用于跨类别错误比对。标准内置的两个 error_category标准库预定义两个全局单例错误类别std::system_category()操作系统原生错误Windows 系统错误、POSIX 系统调用产生的错误码归属这个类别。错误码数值依赖操作系统。std::generic_category()通用可移植错误类别对应传统的errno值跨平台错误码。2.自定义 error_category2.1.实现步骤想要创建一套自己的错误码体系步骤继承std::error_category公有派生重写name()返回类别名称重写message(int err)把错误编号转为文本创建该类的全局单例对象error_category 必须全局唯一实例配套枚举自定义错误码2.2.完整代码#include system_error #include string #include iostream //自定义错误枚举 enum class MyErr{ FileNotFound1, PermissionDenied }; //继承错误类别 class MyErrorCategory : public std::error_category { public: const char* name() const noexcept override { return my_custom_error; } std::string message(int ev) const override { switch(static_castMyErr(ev)) { case MyErr::FileNotFound: return 文件不存在; case MyErr::PermissionDenied:return 权限不足; default:return 未知自定义错误; } } }; //全局唯一单例 const std::error_category my_error_category() { static MyErrorCategory cat; return cat; } //把枚举转为error_code std::error_code make_error_code(MyErr e) { return std::error_code(static_castint(e),my_error_category()); } namespace std{ //模板特化让标准库识别MyErr可以作为错误码 template struct is_error_code_enumMyErr:public std::true_type{}; } int main() { std::error_code ec MyErr::FileNotFound; std::cout ec.category().name() \n; std::cout ec.message() std::endl; return 0; }类型特征启用枚举隐式转换// 枚举可隐式转为 error_code templateclass T struct is_error_code_enum : false_type {}; // 枚举可隐式转为 error_condition templateclass T struct is_error_condition_enum : false_type {}; // 使用示例 namespace std { template struct is_error_code_enumMyErr : true_type {}; }辅助工厂函数// 标准库内置 error_code make_error_code(errc e) noexcept; error_condition make_error_condition(errc e) noexcept; // 你自己需要实现 error_code make_error_code(MyErr e);std::system_error 异常class system_error : public runtime_error { public: system_error(error_code ec); system_error(error_code ec, const string what_arg); system_error(int ev, const error_category cat); system_error(int ev, const error_category cat, const string what_arg); const error_code code() const noexcept; const char* what() const noexcept override; };2.3.error_code、error_condition、error_category 三者关系std::error_code由错误数值 error_category 类别组合而成唯一确定一个错误。error_category是错误的归属相同数字不同类别代表完全不一样的错误。error_condition是通用错误条件用于跨平台比较错误。2.4.常见误区1. 不要在栈上创建error_category对象必须静态全局单例因为error_code保存对 category 的引用栈对象会导致野引用。2. 错误码数值不要随意重复同一类别内错误编号唯一。error_category对象以地址作为唯一性判断依据。两个error_code类别相等的判断方式是直接比较 category 对象的地址而非name()字符串这也是必须单例的根本原因。//底层比较方式 bool operator(const error_code lhs,const error_code rhs) noexcept{ return lhs.category()rhs.category() lhs.value()rhs.value(); }2.5.关键要点总结error_category是抽象基类不可以直接实例化只能继承。每个错误类别必须只有一个全局实例不允许创建多个对象。name()区分不同错误域message()负责错误文本。自定义错误枚举需要特化std::is_error_code_enum才能隐式构造error_code。