商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 编程开发 > C++如何处理异常 _ try-catch捕获与throw用法【实战】

C++如何处理异常 _ try-catch捕获与throw用法【实战】

  发布于2026-07-19 阅读(0)

扫一扫,手机访问

先抛出一个结论:能用 try-catch 捕获的,只有真正被 throw 抛出的 C++ 异常。 像空指针解引用、除零这类系统级错误,默认是不会触发 catch 的,除非编译器开启特定异常机制(比如 Windows 的 SEH 转换)。

看这张图,直观展示了 C++ 异常处理的边界:C++如何处理异常 _ try-catch捕获与throw用法【实战】

什么时候 catch 会完全失效?

很多人以为 catch(...) 能抓一切,真相远没那么简单。它只捕获 C++ 异常对象,对下面这些情况完全无感:

  • 访问野指针或 nullptr 导致的段错误(SIGSEGV),在 Linux/macOS 下直接进程终止,catch 根本来不及反应
  • int x = 1 / 0; —— 这是 CPU 级别的 trap,C++ 标准压根不把它定义为异常
  • 栈溢出、内存耗尽(new 失败时,只有开了 nothrow 才会抛 std::bad_alloc

验证方法很简单:写个 throw 42; 能被捕获;但 *(int*)0 = 1; 会直接 crash,catch(...) 连运行的机会都没有。

throw 表达式必须匹配 catch 类型吗?

必须匹配,但规则比表面严格。不是“能转就行”,而是要求类型相同、公有继承、或有可调用的拷贝/移动构造函数:

  • throw std::runtime_error("msg"); → 可被 catch(std::exception& e) 捕获(公有继承)
  • throw "hello"; → 只能被 catch(const char*) 捕获,catch(std::string) 不行(隐式转换不参与匹配)
  • throw 3.14;catch(int) 捕不到,catch(double) 才行

核心建议:始终抛 std::exception 派生类,避免基础类型传递导致的切片或生命周期问题。

为什么 catch 参数推荐用引用?

值传递会触发异常对象拷贝,可能抛新异常(比如拷贝构造函数里 new 失败),导致栈展开中断、程序终止。看这个例子:

class BadCopy {public:    BadCopy() = default;    BadCopy(const BadCopy&) { throw std::runtime_error("copy failed"); }};// ...try {    throw BadCopy{};} catch(BadCopy b) { /* 这里会二次崩溃 */ }

正确写法只有一种:

  • catch(const std::exception& e) —— 安全、高效、支持多态
  • 避免 catch(std::exception e)(值传递)和 catch(std::exception&& e)(仅匹配右值,漏掉大部分情况)

资源泄漏风险:throw 发生在构造函数里怎么办?

构造函数中途 throw,已构造的成员会自动析构,但裸指针、文件描述符等不会。看个错例:

  • 错例:FILE* fp = fopen("x.txt", "r"); if (!fp) throw std::runtime_error("open fail"); —— fopen 成功后若后续 throw,fp 泄漏
  • 正解:用 RAII 封装,比如 std::unique_ptrstd::ifstream
  • 更彻底的做法:把资源获取逻辑移到工厂函数中,构造函数只做轻量初始化

记住:C++ 异常安全的唯一可靠路径是 RAII,不是靠 try-catch 到处兜底。

话题回到最容易忽略的一点:noexcept 函数里如果意外抛出异常,程序会立刻调用 std::terminate,连 catch(...) 都来不及触发。检查第三方库接口是否标记 noexcept,比写 try 更关键。

本文转载于:https://www.php.cn/faq/2314072.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。

热门关注