c++中catch必须声明形参,如catch(const std::exception& e),仅写类型非法;throw只能抛标准异常对象;main内try-catch无法捕获全局构造、多线程等场景异常;应优先使用noexcept而非throw()。

catch 里为什么不能只写类型不写变量名
因为 C++ 标准要求 catch 子句必须声明一个形参(哪怕你不打算用它),否则编译直接报错:expected parameter name。光写 catch (std::runtime_error) 是非法的,必须写成 catch (std::runtime_error& e) 或 catch (const std::exception& e)。
常见错误现象:编译失败,提示语法错误或“expected ‘)’ before ‘{’”,其实根源就在这儿。
- 推荐始终用
const std::exception&捕获基类,避免切片,也兼容所有派生异常 - 如果需要访问具体信息(比如错误消息),必须绑定变量名,例如
e.what() - 值捕获(
catch (std::runtime_error e))会触发拷贝,不必要且可能抛异常,应避免
throw 表达式后面跟什么才安全
只能 throw std::exception 及其派生类的对象,或者能隐式转为它们的临时对象。直接 throw 字符串字面量(如 throw "oops")或整数,会导致 std::terminate 立即调用——程序直接退出,连栈都不展开。
使用场景:你写库函数、关键路径逻辑,或封装底层系统调用(比如 open() 失败)时,必须确保抛出的是标准异常类型。
立即学习“C++免费学习笔记(深入)”;
- 安全做法:用
throw std::runtime_error("msg")、throw std::logic_error("bad arg") - 自定义异常要继承
std::exception或其子类,并重载what() - 不要 throw 指针(
throw new std::runtime_error(...)),没人负责 delete,必然泄漏
try-catch 放在 main 里能兜住所有异常吗
不能。main 函数外的静态/全局对象构造函数中抛出的异常、线程函数里未捕获的异常、信号转换成的异常(如用 std::set_terminate 配合 sigaction)、以及 std::thread 启动后主线程没 join 就退出,都会绕过 main 里的 try-catch。
性能影响:顶层 try-catch 本身开销极小,但掩盖了“异常未被处理”的事实,容易让问题延迟暴露。
- main 中的 try-catch 仅对 main 函数体内抛出的异常有效
- 多线程环境下,每个线程需独立设 try-catch,否则异常会终止整个线程并可能调用
std::terminate - 全局对象初始化失败时,程序直接终止,无法 catch —— 这是 C++ 的硬限制
noexcept 和 throw() 声明怎么选
全用 noexcept,别碰 throw()。后者是 C++98 的废弃特性,C++17 起已被移除;而 noexcept 是现代写法,编译器能据此做优化(比如移动操作是否可无异常地调用)。
容易踩的坑:声明了 noexcept 却在函数体里抛异常,会立刻调用 std::terminate,不会跳到最近的 catch。
- 移动构造/赋值、析构函数、swap 等关键接口,建议显式加
noexcept -
noexcept(true)和noexcept等价;noexcept(false)表示可能抛异常 - 模板函数慎用
noexcept,除非你能保证所有实例化路径都安全,否则用noexcept(noexcept(expr))条件推导










