试分析推断下述代码的输出结果:
#include <stdio.h> #include <stdlib.h> #include <exception> using namespace std; void* operator new(size_t size) { printf("my new -> %u\n", size); return malloc(size); } void operator delete(void *p) { printf("mydelete\r\n"); return free(p); } class A { public: A() { printf("A\n"); throw int(-1); } ~A() { printf("~A\n"); } }; int main() { A* p = NULL; try { p = new A; } catch (int& i) { printf("exception -> %d\n", i); } return 0; }
要知道上述代码的输出结果,可能需要知道C++的new到底做了什么,以及如果析构函数抛出异常的话,C++是如何处理这种情况的。
实际上,上述代码的输出结果是:
my new -> 1 A mydelete exception -> -1
实际上,当new一个对象时,C++首先需要分配对象的内存,然后才会调用对象的析构函数,而且C++会调用new(sizeof(T))函数分配内存。其大致过程如下所示:
//new 实际过程大致是是: A* p = (A*)malloc(sizeof(A)); try { A(); } catch(...) { // 保证异常后不会造成内存泄露 // 不会调用析构函数(对象都没创建成功,析构函数没意义了) delete p; throw exception; }
此外,当new过程中发现构造函数抛出异常而且构造函数没能处理该异常的话,那么C++就会使得该对象的创建失败,同时会释放已经分配好的内存,但是需要注意的是,此时C++不会去掉用对象的析构函数。
所以由上述知识我们就可以具体分析上述代码的输出结果了。
因此,对于构造函数抛出异常的情况,我们可做下述分析:
#include <stdio.h> #include <stdlib.h> #include <exception> using namespace std; // 重载new void* operator new(size_t size) { printf("my new -> %u\n", size); return malloc(size); } // 重载delete void operator delete(void *p) { printf("mydelete\r\n"); return free(p); } class A { public: A() { printf("A\n"); // 析构函数抛出异常 // C++自动会释放已分配的内存但是不会调用析构函数 throw int(-1); } ~A() { printf("~A\n"); // 析构函数不推荐抛出异常,如果一定要,要自我实现异常处理 } }; int main() { A* p = NULL; try { // 此处实际调用 operator new (sizeof(A)) // 如果构造函数抛出了异常new的返回值为NULL p = new A; } catch (int& i) { printf("exception -> %d\n", i); } return 0; }
时间: 2024-11-08 18:57:51