c++中catch必须指定类型,空参数不合法;推荐catch(const std::exception& e);throw应避免局部指针和new对象;析构函数禁止throw;需显式启用-fexceptions支持异常。

catch 里必须写类型,不能只写 catch {...}
不写类型就捕获不到任何异常,C++ 标准根本不允许空参数的 catch。常见错误是照着其他语言习惯写成 catch {...},结果编译直接报错:expected type-specifier before ‘{’ token。
正确写法只有三种常见形式:
-
catch (const std::exception& e)—— 捕获所有标准异常(推荐起点) -
catch (int e)—— 捕获抛出的int(比如throw 42;) -
catch (...)—— 捕获所有类型(包括非std::exception子类),但无法获取异常信息,慎用
throw 的对象最好别是局部变量或裸指针
抛出局部对象本身没问题(会自动拷贝或移动),但很多人误 throw 局部指针,比如:throw &e;,结果 catch 里拿到的是悬垂地址。
更隐蔽的问题是 throw 临时对象后被优化掉、或 move 构造失败导致未定义行为。稳妥做法:
立即学习“C++免费学习笔记(深入)”;
- 统一用
throw std::runtime_error("msg")这类标准异常类型 - 自定义异常类时,确保有公有无参构造函数和拷贝/移动语义
- 避免
throw new std::exception(...)—— new 出来的对象没人 delete,内存泄漏
析构函数里别 throw,否则程序直接 terminate
C++ 规定:如果在栈展开过程中(也就是正在处理一个异常时)又抛出新异常,且当前异常尚未被处理,std::terminate() 会被调用,进程退出 —— 不会进任何 catch。
而析构函数天然处于栈展开路径上,所以:
- 析构函数里禁止
throw(连throw()异常说明都已废弃) - 如果析构中可能出错(比如文件关闭失败),只能记录日志、设标志位,不能抛
- 用
noexcept显式标注析构函数(现代 C++ 默认已是noexcept)
没加 -fexceptions 时,try-catch 可能完全失效
某些嵌入式或精简构建环境(如部分 ARM GCC 工具链、-Oz 编译选项下)默认禁用异常支持。这时即使写了 try/catch,throw 也会直接 abort,不会跳转到 catch 块。
确认方法很简单:
- 编译时加
-fexceptions(GCC/Clang 必须显式开启) - 检查链接器是否带
-lstdc++(尤其静态链接时) - 运行时测试:写个最小
throw std::logic_error("")看是否被捕获
这个开关不生效时,错误现象非常迷惑:代码看着全对,但就是不进 catch,也看不到崩溃堆栈 —— 容易以为是逻辑问题,其实是编译配置漏了。











