必须用 const std::exception& 捕获,否则按值捕获会导致派生类对象切片;析构函数抛异常会调用 std::terminate;未捕获异常在 main 外直接终止程序;异常不可跨线程传播;std::string 构造不保证抛异常,空指针为未定义行为。

catch 捕获不到 std::exception 子类?检查抛出对象是不是临时对象被切片了
常见现象是:明明 throw std::runtime_error("msg"),但 catch (std::exception e) 里拿到的却是空消息或崩溃。问题出在按值捕获——std::exception 是基类,按值传参会触发对象切片,丢失派生类信息。
- 必须用引用捕获:
catch (const std::exception& e),否则所有子类(std::runtime_error、std::logic_error等)都会被截断 - 不要写
catch (std::exception e)或catch (std::exception* e)(后者根本捕不到栈上抛出的对象) - 如果想捕获所有异常,
catch (...)可以兜底,但它不提供任何错误信息,不能直接调e.what()
try-catch 放错位置导致程序直接 terminate
C++ 异常未被捕获时会调用 std::terminate,进程退出且不打印堆栈。这不是 bug,是标准行为——说明你漏写了某层 catch,或者异常从析构函数里逃出来了。
- 析构函数默认是
noexcept的,如果里面抛异常(比如std::ofstream关闭失败),会立即调std::terminate;务必用noexcept(false)显式标注,或改用try/catch在内部处理 - 全局
main()函数外没 try 块,任何未捕获异常都会终止;建议在main()开头加一层try { ... } catch (...) { return 1; }防止静默崩溃 - 多线程中,异常只在抛出它的线程内传播;其他线程里的
try对它完全无效
为什么 std::string 构造失败会抛 std::bad_alloc 而不是 std::invalid_argument?
这是 C++ 标准库实现细节决定的:内存分配失败统一走 std::bad_alloc,和参数合法性无关。别指望靠 catch std::invalid_argument 来处理空指针构造 std::string 这种情况。
-
std::string s(nullptr)是未定义行为,不抛异常,可能直接段错误;必须先判空 -
std::string s(ptr, n)中若n超过实际缓冲区长度,行为未定义;标准不保证抛异常 - 真正会稳定抛
std::bad_alloc的场景只有内存耗尽,比如std::string(1024*1024*1024, 'x')在小内存机器上
性能影响:频繁 throw/catch 会拖慢程序吗?
会,但仅限于“真的抛出并展开栈”的时候。try/catch 语句本身(没触发异常时)几乎零开销,现代编译器已优化掉大部分运行时负担。
立即学习“C++免费学习笔记(深入)”;
- 异常抛出是重量级操作:要遍历栈帧、调析构、找匹配 handler,比 if-else 判断慢 1–2 个数量级
- 不要用异常做流程控制,比如用
throw代替return表达“找不到”;该用std::optional或返回码就用 - Release 模式下,异常处理机制仍存在,但部分调试信息(如符号名)会被剥离,
what()内容可能变简略
事情说清了就结束。异常机制本身不难,难的是判断哪些错误真该用它来表达——比如资源获取失败、协议解析错误这类“意外”,而不是“输入为空”这种可预期分支。








