【异常机制】异常抛出变量的生命周期

简介: 【异常机制】异常抛出变量的生命周期

当我们throw出类对象时,使用catch捕获异常时有三种选择,分别是捕获对象元素、捕获引用和捕获指针,那么这三种情况下,捕获到的变量是如何分配内存,他的生命周期又是如何呢,首先结论如下:

  • 捕获类对象的元素:调用拷贝构造函数把抛出的对象元素拷贝给catch的参数对象元素,调用拷贝构造函数;
  • 捕获类对象的引用:catch语句中的对象直接使用抛出的对象;
  • 捕获类对象的指针:需要手动new和delete控制内存;

结论如上,下面通过一个程序详细探究(提示:因为catch严格按照类型匹配进行接异常,所以catch元素和catch引用不能同时出现)。

1. #include <iostream>
2. using namespace std;
3. 
4. class pIsNULL
5. {
6. public:
7.  pIsNULL()
8.  {
9.    cout << "pIsNULL 无参构造函数" << endl;
10.   }
11.   //pIsNULL(pIsNULL& p)
12.   //错误  C2440 “throw” : 无法从“pIsNULL”转换为“pIsNULL”
13.   //错误(活动)  E0334 类 "pIsNULL" 没有适当的复制构造函数 
14.   pIsNULL(const pIsNULL& p) //拷贝构造函数要加 const
15.   {
16.     cout << "pIsNULL 拷贝构造函数" << endl;
17.   }
18.   ~pIsNULL()
19.   {
20.     cout << "pIsNULL 析构函数" << endl;
21.   }
22. public:
23.   void print_err_type()
24.   {
25.     cout << "异常原因:指针指向NULL" << endl;
26.   }
27. };
28. 
29. void print_str(char* str)
30. {
31.   if (str == NULL)
32.   {
33.     throw pIsNULL(); //调用无参构造函数
34.   }
35.   cout << str << endl;
36. }
37. 
38. void TestFunc1()
39. {
40.   char buf1[] = "hello";
41.   char* buf2 = NULL;
42. 
43.   try
44.   {
45.     print_str(buf2);
46.   }
47.   catch (pIsNULL e) //调用拷贝构造函数,将 throw 出的对象复制给 e
48.   {
49.     e.print_err_type();
50.   }
51.   catch (...)
52.   {
53.     cout << "未知异常" << endl;
54.   }
55. }
56. 
57. void TestFunc2()
58. {
59.   char buf1[] = "hello";
60.   char* buf2 = NULL;
61. 
62.   try
63.   {
64.     print_str(buf2);
65.   }
66.   catch (pIsNULL& e) //不会调用拷贝构造函数
67.   {
68.     e.print_err_type();
69.   }
70.   catch (...)
71.   {
72.     cout << "未知异常" << endl;
73.   }
74. }
75. 
76. void print_str2(char* str)
77. {
78.   if (str == NULL)
79.   {
80.     throw new pIsNULL;
81.   }
82.   cout << str << endl;
83. }
84. 
85. void TestFunc3()
86. {
87.   char buf1[] = "hello";
88.   char* buf2 = NULL;
89. 
90.   try
91.   {
92.     print_str2(buf2);
93.   }
94.   catch (pIsNULL* e)
95.   {
96.     e->print_err_type();
97.     delete e;
98.   }
99.   catch (...)
100.  {
101.    cout << "未知异常" << endl;
102.  }
103. }
104. 
105. int main()
106. {
107.  TestFunc1(); //用对象元素接异常
108.  //TestFunc2(); //用引用接异常
109.  //TestFunc3(); //用指针接
110. 
111.  system("pause");
112.  return 0;
113. }

分别在主函数中调用三个测试函数,观察打印结果:

①在主函数中调用第一个测试函数,用元素捕获异常

TestFunc1(); //用对象元素接异常

打印结果如下

可以看到,在catch的时候会将throw处构造的对象通过拷贝构造函数复制给catch语句中的元素e,因为这里一共有两个对象,所以在异常结束时会调用两次析构函数,分别析构两个对象。

②在主函数调用第二个测试函数,用引用捕获异常

TestFunc2(); //用引用接异常

运行结果如下

使用引用捕获异常的时候会直接使用throw处构造的对象,所以不会调用拷贝构造函数,只调用一次析构函数

③在主函数调用第三个测试函数,用指针捕获异常

TestFunc3(); //用指针接

抛出指针类型的异常最好手动new和delete来管理内存。


相关文章
|
7月前
|
算法 编译器 C语言
【C++ 异常】C++ 标准库异常类及其应用
【C++ 异常】C++ 标准库异常类及其应用
90 0
|
7月前
|
Java C++ Spring
解决NoUniqueBeanDefinitionException异常的方法
了解Spring框架中`NoUniqueBeanDefinitionException`异常的原因和解决方案。此异常发生在容器内有多个相同类型的bean时,Spring无法决定注入哪个bean。解决方法包括:使用`@Primary`注解标记首选bean,利用`@Qualifier`注解配合`@Autowired`、`@Resource`、`@Inject`或`@Value`指定bean名称。选择哪种方法取决于业务需求和具体场景,预防措施是避免创建多个同类型bean或使用`@Primary`注解。
252 0
|
1月前
|
安全 Java 测试技术
如何避免静态变量初始化中的异常
在Java中,静态变量初始化时可能会遇到异常。为避免此类问题,可以采取以下措施:1. 使用静态代码块进行初始化;2. 确保初始化逻辑简单且安全;3. 捕获并处理可能的异常。这些方法能有效提高程序的健壯性和稳定性。
61 15
|
2月前
|
监控 Java
捕获线程执行异常的多种方法
【10月更文挑战第15天】捕获线程执行异常的方法多种多样,每种方法都有其特点和适用场景。在实际开发中,需要根据具体情况选择合适的方法或结合多种方法来实现全面有效的线程异常捕获。这有助于提高程序的健壮性和稳定性,减少因线程异常带来的潜在风险。
29 1
|
7月前
|
Java 测试技术 数据库
你遇到过哪些触发NPE的代码场景?
【5月更文挑战第18天】空指针异常(NPE)是开发过程中常见的障碍,它不仅阻碍了代码的正常运行,还常常成为系统不稳定性的根源。本文讲述关于如何避免NPE的一些看法。
|
前端开发 JavaScript
【JavaScript】Promise(零) —— 准备工作(实例对象、函数对象、回调函数分类、捕获抛出错误)
【JavaScript】Promise(零) —— 准备工作(实例对象、函数对象、回调函数分类、捕获抛出错误)
|
Java 开发者
JAVA异常类异常抛出处理
JAVA异常类异常抛出处理
137 0
|
Java
编写一个程序,它能导致JVM抛出一个OutOfMemoryError,然后捕获和处理这个异常
编写一个程序,它能导致JVM抛出一个OutOfMemoryError,然后捕获和处理这个异常
206 0
有关异常的处理、捕获、抛出、自定义
有关异常的处理、捕获、抛出、自定义
108 0
|
C++
【C++ 语言】异常 ( 抛出字符串异常 | 抛出异常对象 | 抛出任意对象 | 抛出自定义异常 )(一)
【C++ 语言】异常 ( 抛出字符串异常 | 抛出异常对象 | 抛出任意对象 | 抛出自定义异常 )(一)
138 0