在编程中,异常(Exception)是指在程序执行过程中出现的错误或意外情况,它会导致程序的正常流程中断,程序控制会转移到一个专门处理错误的区域。异常处理机制的主要目的是让程序在遇到错误时能够优雅地退出,或者做出相应的处理,避免程序崩溃。
#include <iostream>
#include <stdexcept> // 包含标准异常类
using namespace std;
// 自定义异常类(继承自exception)
class NegativeValueError : public exception {
public:
const char* what() const noexcept override {
return "错误:不允许负值参数";
}
};
// 可能抛出异常的函数
double calculate_sqrt(double value) {
if (value < 0) {
throw NegativeValueError(); // 抛出自定义异常
}
return sqrt(value);
}
// 另一个可能抛出异常的函数
int divide_numbers(int a, int b) {
if (b == 0) {
throw runtime_error("错误:除数不能为零"); // 抛出标准异常
}
if (a % b != 0) {
throw "结果不是整数"; // 抛出原始字符串(不推荐,仅作演示)
}
return a / b;
}
int main() {
try {
// 测试平方根计算
cout << "计算sqrt(4): ";
cout << calculate_sqrt(4) << endl;
cout << "计算sqrt(-1): ";
cout << calculate_sqrt(-1) << endl; // 这里会抛出异常
// 测试除法运算
cout << "\n10 / 2 = ";
cout << divide_numbers(10, 2) << endl;
cout << "5 / 0 = ";
cout << divide_numbers(5, 0) << endl; // 这里会抛出异常
cout << "7 / 3 = ";
cout << divide_numbers(7, 3) << endl; // 这里会抛出异常
} catch (const NegativeValueError& e) { // 捕获自定义异常
cerr << "捕获到自定义异常: " << e.what() << endl;
} catch (const runtime_error& e) { // 捕获标准异常
cerr << "捕获到运行时错误: " << e.what() << endl;
} catch (const char* msg) { // 捕获原始字符串异常
cerr << "捕获到字符串异常: " << msg << endl;
} catch (...) { // 捕获所有其他异常
cerr << "捕获到未知异常" << endl;
}
cout << "\n程序继续执行..." << endl;
return 0;
}
输出结果:
计算sqrt(4): 2 计算sqrt(-1): 捕获到自定义异常: 错误:不允许负值参数 程序继续执行…
栈展开(Stack Unwinding)是 C++ 异常处理机制中的核心概念之一。当异常被抛出且未被当前作用域捕获时,程序会沿着调用链逐层销毁局部对象(即栈上的对象),直到找到匹配的 catch 块为止。这个过程称为栈展开。
#include <iostream>
using namespace std;
class MyClass {
public:
MyClass(int id) : id_(id) {
cout << "对象 " << id_ << " 构造" << endl;
}
~MyClass() {
cout << "对象 " << id_ << " 析构" << endl;
}
private:
int id_;
};
void func3() {
MyClass obj3(3); // 局部对象
throw runtime_error("异常发生!");
}
void func2() {
MyClass obj2(2); // 局部对象
func3();
}
void func1() {
MyClass obj1(1); // 局部对象
func2();
}
int main() {
try {
func1();
} catch (const exception& e) {
cerr << "捕获异常: " << e.what() << endl;
}
cout << "程序继续执行..." << endl;
return 0;
}
输出结果:
对象 1 构造 对象 2 构造 对象 3 构造 对象 3 析构 对象 2 析构 对象 1 析构 捕获异常: 异常发生! 程序继续执行…
上述文字说的很抽象,通过代码来讲解上述枯燥的文字。
#include <iostream>
#include <stdexcept>
using namespace std;
// 派生类转基类示例
class Base { virtual void foo() {} };
class Derived : public Base {};
// 自定义异常类
class MyException : public exception {
public:
const char* what() const noexcept override {
return "自定义异常:派生类转基类失败";
}
};
int main() {
try {
// 类型转换示例 1:非常量转常量
int num = 42;
const int& cnum = num;
// 类型转换示例 2:数组转指针
int arr[5] = { 1,2,3,4,5 };
int* ptr = arr;
// 类型转换示例 3:函数转指针
void (*funcPtr)(int) = [](int x) { cout << "Lambda: " << x << endl; };
funcPtr(10);
// 类型转换示例 4:派生类转基类
Derived d;
Base* b = &d;
// 异常抛出示例
if (b == nullptr) throw MyException();
throw runtime_error("运行时错误:空指针异常");
}
catch (const MyException& e) { // 精确捕获
cerr << "捕获特定异常: " << e.what() << endl;
}
catch (const exception& e) { // 标准异常捕获
cerr << "捕获标准异常: " << e.what() << endl;
}
catch (...) { // 兜底捕获(无法获取具体信息)
cerr << "捕获未知异常(无法获取详细信息)" << endl;
}
return 0;
}
exception是所有异常的基类,可以捕获任何异常。 输出结果:
Lambda: 10 捕获标准异常: 运行时错误:空指针异常
异常重新抛出(Re-throwing Exceptions)是 C++ 异常处理中的重要机制,允许在捕获异常后将其原样或修改后再次抛出。 语法:
try {
// 可能抛出异常的代码
} catch (const SomeException& e) {
// 预处理逻辑(如记录日志)
throw; // 重新抛出原始异常(保持类型不变)
}
示例代码:
#include <iostream>
#include <stdexcept>
using namespace std;
void process_data(int value) {
if (value < 0) {
throw invalid_argument("值不能为负数");
}
// 处理数据...
}
int main() {
try {
process_data(-5);//发生异常
} catch (const exception& e) {//处理异常
cerr << "底层捕获异常: " << e.what() << endl;
// 添加额外处理逻辑(如记录日志)
// throw; // 重新抛出原始异常(类型保持为 invalid_argument)
// 或者抛出新异常(类型改变)
throw runtime_error("数据预处理失败: " + string(e.what()));//异常重新抛出
}
return 0;
}
输出结果:
底层捕获异常: 值不能为负数 terminate called after throwing an instance of ‘std::runtime_error’ what(): 数据预处理失败: 值不能为负数
抛出异常后,可能会导致资源没有机会被正确回收,从而导致内存泄漏。RAII模式可以完美解决该问题。析构函数抛出异常,也需谨慎处理。
C++标准库也定义了⼀套⾃⼰的⼀套异常继承体系库,基类是exception,所以我们⽇常写程序,需要在主函数捕获exception即可,要获取异常信息,调⽤what函数,what是⼀个虚函数,派⽣类可以重写。通过基类指针或引用实现多态行为。
本文系统讲解了C++异常处理机制,涵盖异常概念、抛出捕获、栈展开、异常重新抛出、异常安全及标准异常体系等内容。通过代码示例演示了自定义异常、类型转换异常、资源管理等核心场景,强调RAII模式在异常安全中的关键作用,并对比了C++不同版本异常规范的演变。掌握这些机制可编写更健壮的C++程序,有效处理运行时错误,避免资源泄漏
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有