catch捕不到std::terminate是因为未抛出异常,空指针解引用等是未定义行为而非异常;应显式throw或用标准库抛异常函数;catch(const std::exception&)比catch(...)更安全且类型明确。

catch 捕不到 std::terminate 是因为没抛出异常
很多 C++ 新手写完 try-catch 发现完全不进 catch 块,程序直接崩了——这通常不是 catch 失效,而是根本没触发异常机制。C++ 不会自动把空指针解引用、数组越界、除零等行为转成异常;它们是未定义行为(UB),直接导致崩溃或静默错误。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 只有显式调用
throw,或标准库函数(如std::vector::at()、std::stoi())在特定条件下抛出的异常,才能被catch捕获 - 想让越界访问可捕获?改用
vec.at(i)而非vec[i];后者不抛异常,前者在越界时抛std::out_of_range - 除零不抛异常,但你可以自己检查:
if (b == 0) throw std::invalid_argument("division by zero");
catch(const std::exception&) 为什么比 catch(...) 更安全
用 catch(...) 确实能兜住所有异常,但它抹掉了类型信息,你无法知道发生了什么,也难以做针对性处理。更糟的是,它还会捕获非 std::exception 派生的类型(比如 int 或原始指针),这些往往不是设计来当异常用的。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 优先用
catch(const std::exception& e),它能捕获所有标准异常,且保证对象生命周期安全(避免切片) - 需要区分具体错误?按继承顺序从具体到宽泛排列:
catch(const std::out_of_range&)→catch(const std::runtime_error&)→catch(const std::exception&) - 绝不要只写
catch(...)后什么都不做(空 catch 块),这等于吞掉错误,调试时无迹可寻
析构函数里 throw 会导致 std::terminate
C++ 明确禁止在析构函数中抛出未被捕获的异常。一旦发生,程序立即调用 std::terminate 终止,连堆栈都不展开。这不是 bug,是语言设计:栈展开(stack unwinding)过程中若另一个异常抛出,系统无法决定该处理哪个。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 析构函数必须是
noexcept(C++11 起默认隐式声明为noexcept) - 如果析构中可能出错(比如关闭文件失败),不要
throw,改用日志记录、设置标志位、或调用std::abort()(仅限严重错误) - 若真需报告错误,考虑把资源管理逻辑移到普通成员函数中,让调用者决定是否
try-catch
自定义异常类要继承 std::exception 并重写 what()
直接 throw "string" 或 throw 42 虽语法合法,但无法被 catch(const std::exception&) 捕获,破坏统一错误处理流程。自定义异常必须兼容标准异常接口。
实操建议:
立即学习“C++免费学习笔记(深入)”;
- 继承
std::runtime_error(而非裸std::exception)最省事,它已实现what()和构造函数转发 - 别在
what()里返回局部变量地址或临时字符串;推荐用std::string成员 +c_str()返回其内部指针 - 示例:
class FileOpenError : public std::runtime_error { public: explicit FileOpenError(const std::string& path) : std::runtime_error("Failed to open: " + path) {} };
noexcept 声明、RAII 的严格守卫、以及日志里保留原始错误码,比 catch 块本身更重要。











