在C++函数设计中,异常处理通常依赖标准库提供的std::exception体系,但实际项目中经常遇到抛出非标准异常的情况,例如直接throw 1或者throw "error",这类异常无法被catch(const std::exception& e)捕获。为了让程序更稳定,我们需要一套机制在函数中处理这些非标准异常。

什么是非标准异常
非标准异常指的是没有继承std::exception类型的被抛出的对象。常见形式包括基础类型、C风格字符串、以及未接入标准体系的自定义结构体。它们在类型系统中与标准异常完全隔离。
- throw -1;
- throw "network fail";
- throw MyOldError(); 其中MyOldError未继承std::exception
使用catch(...)捕获并转换
函数内部可以用catch(...)捕获所有异常,然后将其转化为标准异常重新抛出,使上层调用统一处理。
#include <stdexcept>
#include <string>
void old_api_call(); // 可能抛出非标准异常
void safe_wrapper() {
try {
old_api_call();
} catch (const std::exception& e) {
throw; // 标准异常直接透传
} catch (const char* msg) {
// 将C字符串非标准异常转为标准异常
throw std::runtime_error(std::string("c str error: ") + msg);
} catch (...) {
// 其余非标准异常统一处理
throw std::runtime_error("unknown non-standard exception");
}
}
结合std::current_exception判断
在catch(...)中可通过std::current_exception获取异常指针,延迟到外层做类型分发,适合写通用中间件函数。
#include <exception>
#include <stdexcept>
void handle_any() {
try {
throw 42; // 非标准异常
} catch (...) {
std::exception_ptr ep = std::current_exception();
try {
std::rethrow_exception(ep);
} catch (int i) {
// 针对整数非标准异常做日志
} catch (const std::exception& e) {
// 标准异常
} catch (...) {
// 其他
}
}
}
noexcept的影响
如果函数声明为noexcept,内部抛出非标准异常会导致直接调用std::terminate。因此包装非标准异常的函数不宜随意标noexcept,除非已确保所有路径都被捕获。
| 函数声明 | 非标准异常结果 |
|---|---|
| void f(); | 向上传播 |
| void f() noexcept; | 程序终止 |
实践建议
建议在模块边界统一使用包装函数,把历史接口的非标准异常转成std::runtime_error或自定义标准异常子类,这样业务代码只需要catch标准类型,降低维护成本。
注意:catch(...)必须放在所有具体catch之后,否则会拦截本应由上层处理的标准异常。
完整示例
#include <iostream>
#include <stdexcept>
void legacy() {
throw "legacy error";
}
void wrapper() {
try {
legacy();
} catch (const std::exception& e) {
throw;
} catch (const char* s) {
throw std::runtime_error(s);
} catch (...) {
throw std::runtime_error("unknown");
}
}
int main() {
try {
wrapper();
} catch (const std::exception& e) {
std::cout << e.what() << std::endl;
}
return 0;
}
C++异常处理非标准异常std_exception修改时间:2026-07-29 01:36:24