c++异常处理try catch_c++ exception使用教程

14次阅读

c++catch必须声明类型,不可写catch();正确写法如catch(std::exception& e),省略变量名也需写类型,否则编译报错。

c++异常处理try catch_c++ exception使用教程

catch 里必须写类型,不能只写 catch()

很多刚学 C++ 的人会误以为 catch() 是万能兜底,结果编译直接报错:Error: expected type-specifier before ')' Token。C++ 标准强制要求每个 catch 必须声明一个带类型的参数(哪怕你不用它),哪怕是省略变量名,也得写类型。

常见写法对比:

try {     throw std::runtime_error("boom"); } catch (std::exception& e) {     // ✅ 正确:引用捕获,避免拷贝     std::cout << e.what() << "n"; } catch (...) {                    // ✅ 正确:C++ 唯一允许的无类型 catch,但只能放最后     std::cout << "unknown exceptionn"; }

错误写法(编译不过):

catch () { ... }           // ❌ 编译失败 catch (auto e) { ... }     // ❌ C++17 也不支持 auto 在 catch 参数中(除非用模板 catch,但那是高级用法) catch (std::exception e) { // ⚠️ 能编译,但会触发异常对象拷贝,可能抛异常(不推荐)

throw 表达式后面不能跟 void 或空语句

throw 是表达式,不是语句;它必须有操作数(即抛出的对象),且该对象类型需可复制或可移动。常见踩坑点:

立即学习C++免费学习笔记(深入)”;

  • 写成 throw;(重抛)是合法的,但**只能出现在已处于异常处理流程中的 catch 块内**;在 try 块或普通函数里单独写 throw; 会导致未定义行为(通常 terminate)
  • throw void();throw nullptr;throw 0; 都可能编译通过,但语义混乱——除非你明确设计了对应类型的 catch,否则几乎一定漏捕获
  • 抛出局部对象时注意生命周期:throw std::String("hello"); 安全(临时对象会被复制/移动),但 throw local_str;(其中 local_strstd::string)也安全,因为 throw 会调用拷贝/移动构造

noexcept 函数里 throw 会直接 terminate

如果函数声明了 noexcept(包括隐式 noexcept(true),比如析构函数、移动操作符),而内部却执行了 throw,程序不会进入 catch,而是立即调用 std::terminate() —— 连 catch(...) 都拦不住。

典型场景:

  • 自定义析构函数里调用了可能抛异常的函数(如 close() 失败返回 -1,但你误 throw)
  • 移动构造函数标记为 noexcept(推荐做法),但内部调用了可能 throw 的容器操作
  • 使用 std::vector::push_back() 等标准库函数时没注意其是否 noexcept(C++11 起多数基础操作已加)

检查方式很简单:看函数声明末尾有没有 noexceptnoexcept(true)。不确定时,宁可不加 noexcept,也不要冒险。

不要在 catch 里“吞掉”异常却不记录

catch(...) { }catch(std::exception&) { return; } 是高危操作,尤其在线程、回调、资源管理上下文中。看似“防止崩溃”,实则掩盖逻辑错误、阻断调试路径、导致资源泄漏(比如本该在异常路径中释放的锁或内存)。

合理做法:

  • 捕获后至少打日志:catch (const std::exception& e) { log_error("failed: ", e.what()); throw; }(重抛)
  • 转换异常类型再抛:catch (const std::system_error& e) { throw MyIoError(e.code(), e.what()); }
  • 仅在明确知道该异常可安全忽略时才空 catch,例如某些平台特定的信号包装异常,且有充分测试覆盖

最常被忽略的一点:析构函数里禁止 throw(C++11 起默认 noexcept),所以即使你想在 catch 中清理,也不能靠抛异常来通知失败 —— 得改用返回码、设置标志位或 abort。

text=ZqhQzanResources