继承 std::exception 是为了接入标准异常体系,支持统一捕获、多态和扩展;必须重写 what() 并加 noexcept,返回长期有效的 const char*;额外信息通过成员变量和访问器携带。

为什么继承 std::exception 而不是直接用字符串 throw?
直接 throw "error" 或 throw 42 虽然语法合法,但无法统一捕获类型、丢失上下文、且不能携带额外信息(如错误码、文件名、行号)。继承 std::exception 是为了接入标准异常体系:能被 catch (const std::exception& e) 捕获,支持多态,也方便后续扩展字段和重载 what()。
自定义异常类必须重写 what() 吗?
是的。基类 std::exception::what() 返回的是空字符串或未定义行为;不重写会导致 e.what() 输出不可靠内容(常见为 "std::exception" 或崩溃)。实际中要确保返回指向**长期有效内存**的 const char*:
- 不能返回局部数组(如
char buf[256]; return buf;) - 不能返回临时
std::string的c_str()(如return std::string("xxx").c_str();) - 推荐用
mutable std::string m_what_cache缓存,每次调用what()时更新并返回其c_str()
示例关键片段:
class FileOpenError : public std::exception {
std::string m_msg;
public:
FileOpenError(const std::string& file)
: m_msg("Failed to open file: " + file) {}
const char* what() const noexcept override {
return m_msg.c_str();
}
};要不要加 noexcept 修饰 what()?
要。C++11 起,std::exception::what() 声明为 noexcept,子类重写时若不加,会隐式变成可能抛异常,导致编译警告甚至 ABI 不兼容(尤其在动态链接场景)。所有重写的 what() 必须带 noexcept。
立即学习“C++免费学习笔记(深入)”;
- 漏写
noexcept可能触发 GCC/Clang 的-Wexceptions警告 - 某些 STL 实现(如 libc++)在异常传播中会检查
what()是否noexcept,否则行为未定义
如何携带错误码、位置信息等额外字段?
标准 std::exception 不提供扩展接口,所以靠成员变量 + 公共访问器。常见做法:
- 添加
int m_errno(如系统调用失败时保存errno) - 添加
const char* m_file和int m_line,通过宏封装构造:throw MyError("msg", __FILE__, __LINE__) - 避免在
what()中拼接耗时操作(如格式化时间戳),只做轻量字符串组合
注意:这些字段不影响 catch 匹配逻辑,仅用于日志或调试输出。
复杂点在于缓存 what() 返回值的生命周期管理——多数人卡在临时对象析构后还去访问 c_str(),结果是随机字符或段错误。










