c++中如何处理异常_c++ try catch异常处理机制【汇总】

2次阅读

throw必须抛出对象而非裸指针或字面量,如throw “Error”或throw nullptr会调用std::terminate();catch需按派生类到基类顺序书写,否则基类catch会截获所有派生异常。

c++中如何处理异常_c++ try catch异常处理机制【汇总】

throw 抛出的必须是对象,不能是裸指针或字面量

很多初学者写 throw "error"throw nullptr,这会导致程序调用 std::terminate() 直接终止。c++ 要求 throw 表达式必须抛出一个可复制(或移动)的完整对象,比如 std::Stringstd::runtime_error,或者自定义的异常类。

  • throw std::runtime_error("file not found") ✅ 安全且带上下文
  • throw 42 ❌ 不推荐:整数不是语义清晰的异常类型,且无法携带消息
  • throw new std::exception() ❌ 危险:抛出的是指针,catch 需手动 delete,极易内存泄漏

catch 块顺序必须从派生类到基类

如果多个 catch 块并存,编译器按书写顺序匹配第一个能接受的类型。若把 catch (const std::exception& e) 写在最前,它会捕获所有派生异常(如 std::logic_error),导致后续更具体的 catch 永远不会执行。

try {     throw std::out_of_range("index too large"); } catch (const std::out_of_range& e) {  // ✅ 必须放前面     std::cerr << "range error: " << e.what() << 'n'; } catch (const std::logic_error& e) {   // ✅ 次之     std::cerr << "logic error: " << e.what() << 'n'; } catch (const std::exception& e) {     // ✅ 最后兜底     std::cerr << "other std exception: " << e.what() << 'n'; }

noexcept 说明符影响异常传播路径

函数声明为 noexcept 后,若内部抛出异常且未被本函数捕获,会立即调用 std::terminate(),而不是向上层传播。这不是“禁止抛出”,而是“承诺不向外传递异常”。

  • void foo() noexcept { throw std::runtime_error("oops"); } → 程序直接终止
  • void bar() noexcept { try { throw ...; } catch (...) { /* handled */ } } ✅ 合法:异常在函数内被吞掉
  • 析构函数默认是 noexcept,因此绝不要在析构函数里抛异常(C++11 起标准禁止)

std::current_exception() 用于跨线程或延迟重抛

普通 throw; 只能在当前 catch 块中重抛当前异常。若想保存异常、跨作用域甚至跨线程再抛出,必须用 std::current_exception() 获取 std::exception_ptr

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

std::exception_ptr saved_exc; try {     risky_operation(); } catch (...) {     saved_exc = std::current_exception(); // 保存异常对象副本 } 

// 在另一段代码中(比如线程回调里) if (saved_exc) { std::rethrow_exception(saved_exc); // 重新抛出原异常,栈信息保留 }

注意:std::exception_ptr 是引用计数的,拷贝安全;但原始异常对象生命周期由其首次抛出处决定,std::current_exception() 会做深拷贝,所以不必担心悬空。

真正容易被忽略的是:异常对象的拷贝构造函数不能抛异常(否则 std::current_exception() 失败时也会 terminate),所以自定义异常类的拷贝构造应声明为 noexcept

text=ZqhQzanResources