c++中如何处理try catch异常_c++异常处理机制详解【难点】

7次阅读

c++要求catch必须声明异常类型,catch{}非法;常用catch(const std::exception& e)或catch(…);析构函数中禁止throw,否则触发std::terminate();noexcept函数内抛异常亦会终止程序;异常对象生命周期限于catch块内。

c++中如何处理try catch异常_c++异常处理机制详解【难点】

catch 里不写类型会编译失败

直接写 catch {} 是非法的,C++ 要求每个 catch 必须声明能捕获的异常类型。最常见的是 catch (const std::exception& e),它能兜住绝大多数标准异常;如果想捕获所有(包括 intchar* 这类非对象异常),得显式写 catch (...) —— 但它不提供异常对象,没法调用 e.what()

容易踩的坑:

  • catch (std::exception e)(传值)会触发拷贝,可能抛新异常或性能差,必须用 const std::exception&
  • catch (std::runtime_error e) 会漏掉 std::logic_error 及其子类,除非你明确只关心这一种
  • catch (...) 后没法知道是什么错,仅适合做日志记录+重新抛出:throw;(注意不是 throw e;

析构函数里 throw 会导致程序终止

C++ 规定:如果在展开过程中(也就是正在执行 catch 或析构函数时)又抛出异常,且当前没有更外层的 catch 捕获它,std::terminate() 会被立即调用 —— 进程直接退出,不跑 atexit、不刷缓冲区。

所以:

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

  • 绝不要在析构函数里写 throw,哪怕你“觉得这里不该出错”
  • 如果析构中可能失败(比如关文件句柄失败),改用返回错误码、记日志、或设标志位,别抛异常
  • noexcept 默认修饰析构函数(C++11 起),显式写 ~MyClass() noexcept 更安全,编译器会帮你拦住误 throw

throw 表达式和 noexcept 不匹配会崩

函数声明了 noexcept,但内部调用了可能抛异常的代码(比如没包 try/catchstd::String::at()),运行时一旦真抛了,就调 std::terminate()

典型场景:

  • 自己写的工具函数标了 noexcept,但里面用了 new(可能抛 std::bad_alloc
  • 调第三方库函数前没查文档,对方没声明 noexcept,你却假设它不会抛
  • std::vector::operator[] 不抛异常,但 at() 会 —— 选错接口就破功

建议:不确定是否抛异常的函数,别轻易标 noexcept;真要标,先包一层 try/catch 把异常吞掉或转成错误码。

异常对象生命周期容易被误解

抛出的异常对象是临时的,存储在特殊内存区,生命周期从 throw 开始,到对应 catch 块结束为止。这意味着:

  • catch 块里取的引用(如 const std::exception& e)是安全的,指向这个临时对象
  • 但千万别把该引用存成成员变量或返回给调用方 —— catch 一退出,对象就销毁,变成悬垂引用
  • 如果需要长期持有异常信息,得拷贝内容:比如 std::string msg = e.what();

复杂点在于:有些编译器对异常对象做 RVO/NRVO 优化,但语义上你不能依赖这点 —— 生命周期规则才是唯一可靠依据。

text=ZqhQzanResources