不看源码的代价就是:只能在表象中猜内层结构
结论写在前头:
1.使用 Type *pointer =new type 或者 Type *pointer =new type()方式都可以申请内存大小,后者调用默认构造函数进行内存初始化;但是,禁用自定义类以及默认类型,
去使用 Type result=Type()结构,编译器会认为这是函数声明而不是自定义类型对象;
2.若使用new指定大小为0的数组对象时,无论有没有括号,不会申请内存,更不会进行初始化内存空间,其操作完毕后指向一个非nulltr空间,故,要注意不能对该指针进行成员操作
最好的预防方式就是申请时进行参数检查。另外,delete 和new操作要相互匹配,即使对空指针两种delete都有效,但是 空的数组对象(长度为0),也要用delete[]形式,而非delete
3.c++new,只需指定数量,自动计算内存大小,失败会直接抛出bad alloc异常,不捕捉则直接terminate,故try...catch ....
除非使用 Type **pointer =new (nothrow) type ,使用该操作就不会抛出异常,行为跟C类似;
而c语言malloc需要之指定申请的大小,即不仅需要输入数量,还需要指定单个元素大小,失败时返回空指针,故使用c编写时要检查空指针
测试:
1.关于new 相关的自定义结构和默认类型的构造测试
2.new &delet空数组测试
结论:如无必要,禁止new空数组,传入参数进行内存申请时最好检测下大小,而不是一来size_t类型做非负数保证,防止非法访存
1 #include<iostream> 2 using namespace std; 3 void result() 4 { 5 cout << "\n\n结论:" << endl; 6 cout << "可以申请长度为0的数组,其理所当然的不会调用定义的析构函数以及构造函数,因为对象本来就没有\n但会产生未定义后果,因此应该对输入进行非正整数判定非法" << endl; 7 cout << "否则,调用成员直接未定义,对成员进行改动则直接在析构时会产生无法预料的后果" << endl; 8 cout << "要么析构调用内存报错,要么无理由程序完成,不析构则内存泄漏+非法访存\n故不要对非法地址进行对象操作,更准确的说应该避免构造空数组\n" << endl; 9 cout << "另外,数组申请为0大小,delete []不会报错,对一个nullptr进行delete[]也不会报错,但直接delete会" << endl; 10 11 12 } 13 14 class k { 15 public: 16 double a = 1; 17 double b; 18 k() { cout << "install" << endl; } 19 k(int x) :a(x) { cout << x << " install" << endl; } 20 k(const k&t) { a = t.a; } 21 k& operator=(const k&t) { a = t.a; } 22 ~k() { cout << "destroy" << endl; } 23 void changeA() 24 { 25 a = 3; 26 cout << "成功函数修改未定义" << endl; 27 } 28 void function(int x) 29 { 30 cout << x << " function 即使是空对象也能调用成员函数" << endl; 31 } 32 }; 33 34 35 int main() 36 { //以下测试是在2019/8月进行,vs2017,win10,debug*86 37 k *fff = nullptr; 38 fff = new k[0]; 39 40 try { 41 if (fff == nullptr)cout << "this is a nullptr" << endl; 42 else 43 { 44 cout << "new k[0] 不返回一个空指针!!! " << endl; 45 //输出一个未定义的系统默认结构则不会退出 46 cout << "输出该指针指向的对象成员 a :" << fff->a << endl; 47 //调用一个函数一样能运行 48 fff->function(3); 49 cout << "该指针指向结构大小 " << sizeof(*fff) << endl; 50 cout << "输出该指针指向数组的长度 :" << sizeof(fff) / sizeof(k) << endl; 51 //试图直接或者以函数接口改动未定义内存是非法的,不会在修改时报错或者不报错直接退出 52 fff->changeA(); 53 fff->a = 4; 54 cout << "成功直接修改未定义值" << endl; 55 56 } 57 //fff = nullptr; //delete[]是合法的 58 delete[]fff; //如果将上面的非法修改操作注释掉,delete[]fff 是合法且不报错的 59 //如果将此析构删除,那么更会带来致命的后果, 60 //即内存泄漏且非法写了未定义的内存而不报错 61 cout << "delete操作运行结束" << endl; //无论是否弹出报错,该语句不会运行,因为程序delete后结束了 62 } 63 catch (exception e) { 64 cout << e.what() << endl; 65 //无法捕捉上诉修改未定义值后,析构的错误,直接退出 66 } 67 result(); 68 }
3.测试自定义结构下是否跟基本类型一样,函数返回内存类型会不会造成内存泄漏
测试方法为使用vs2017 debug功能依次监视各个阶段的内存占用,查看是否成功释放
3.1.直接在代码中静态(直接写明)申请内存,以delete[] 的方式进行显式释放内存-----------------------------------结论:没有发生内存泄漏,内存成功释放
3.2.直接在代码中静态(直接写明)申请内存,以直接delete 的方式进行显式释放内存------------------------------结论:没有发生内存泄漏
3.2.以调用函数的方式,类似静态返回指向内存的指针进行测试 ,并以直接delete的方式进行内存释放 --------------结论:没有发生内存泄漏
3.3; 以非静态大小的方式输入,进行函数返回并delte【】释放测试,测试结果 :依旧没有发生内存泄漏
3.4 动态输入大小的方式进行调整,返回数组内存,使用delete方式进行测试 依旧没有发生内存泄漏