详解C++中动态内存管理和泛型编程
一、C/C内存区域划分1. 栈又叫堆栈--非静态局部变量/函数参数/返回值等等栈是向下增长的。2. 内存映射段是高效的I/O映射方式用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存做进程间通信。3. 堆用于程序运行时动态内存分配堆是可以上增长的。4. 数据段--存储全局数据和静态数据。5. 代码段--可执行的代码/只读常量。二、常见变量存储区域123456789101112131415intglobalVar 1;//全局变量中在静态区staticintstaticGlobalVar 1;//静态区voidTest(){staticintstaticVar 1;//静态区intlocalVar 1;//栈区intnum1[10] { 1, 2, 3, 4 };//栈区charchar2[] abcd;//栈区*char2在栈区constchar* pChar3 abcd;//指针在栈区*pchar3在常量区int* ptr1 (int*)malloc(sizeof(int) * 4);//指针在栈区*ptr1在堆区int* ptr2 (int*)calloc(4,sizeof(int));///栈区int* ptr3 (int*)realloc(ptr2,sizeof(int) * 4);//栈区free(ptr1);free(ptr3);}三、new和delete1、new和delete的使用方式12345678910111213intmain(){int* p1 newint;//在堆区申请一个int大小的空间不会初始化int* p2 newint(0);//申请并初始化为0deletep1;deletep2;int* p3 newint[10];//在堆区申请一块10个int大小的空间未初始化int* p4 newint[10]{ 1,2,3,4 };//初始化为{1,2,3,4,0,0,0,0,0,0}delete[] p3;delete[] p4;return0;}注意申请和释放单个元素的空间使用new和delete操作符申请和释放连续的空间使用new[]和delete[]一定要匹配起来使用。2、new、delete和malloc、free的区别1、对于内置类型没有区别。2、new和delete是C的关键字/操作符而malloc和free是C语言的库函数。3、对于自定义类型相比于malloc和freenew和delete会额外调用类中的构造函数和析构函数。4、malloc的返回值是void*使用时需要强转new后边跟的是空间的类型所以new不需要强转。5、malloc失败返回空指针需要判空new失败抛异常需要捕获异常。3、new的原理new等于operator new()构造函数。operator new()不是new运算符的重载因为参数没有自定义类型。它是一个库里的全局函数。1234567891011121314void*__CRTDECL operatornew(size_tsize) _THROW1(_STD bad_alloc){// try to allocate size bytesvoid*p;while((p malloc(size)) 0)if(_callnewh(size) 0){// report no memory// 如果申请内存失败了这里会抛出bad_alloc 类型异常staticconststd::bad_alloc nomem;_RAISE(nomem);}return(p);}从底层代码可以看出operator new()是对malloc的封装如果malloc失败将会抛出异常。4、delete的原理delete等于operator delete()析构函数12345678910111213141516171819//operator delete: 该函数最终是通过free来释放空间的voidoperatordelete(void*pUserData) {_CrtMemBlockHeader * pHead;RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));if(pUserData NULL)return;_mlock(_HEAP_LOCK);/* block other threads */__TRY/* get a pointer to memory block header */pHead pHdr(pUserData);/* verify block type */_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead-nBlockUse));_free_dbg( pUserData, pHead-nBlockUse );//调用free()__FINALLY_munlock(_HEAP_LOCK);/* release other threads */__END_TRY_FINALLYreturn; }//free的实现#define free(p) _free_dbg(p, _NORMAL_BLOCK)从底层代码可以看出operator delete()调用了free。所以针对内置类型或无资源的类对象delete时使用delete和free效果相同。但对于有资源需要释放的对象时直接使用free虽然释放了对象的空间但对象内部的资源还未被清理导致内存泄漏这种情况必须使用delete。5、new T[N]原理1、new T[N]调用operator new[]2、operator new[]调用operator new完成N个对象空间的开辟。3、调用N次构造函数完成N个对象的初始化。6、delete[]原理1、调用N次析构函数完成N个对象资源的清理工作。2、调用operator delete[]3、operator delete[]调用operator delete完成整段空间的释放。四、定位new1、定位new的概念对于一个类我们可以显式的去调用类的析构函数但是不能显式调用构造函数那么使用定位new就可以显式调用类的构造函数对一块空间重新初始化。2、定位new的使用格式new (指针)类名或者new (指针) type(初始化列表)123456789intmain(){Date d1;new(d1)Date;//new (指针)类名Date* p newDate[4]{ {2022,10,15},{2023,11,8} };new(p)Date[4];//new (指针) type(初始化列表)delete[] p;return0;}上述代码一共调用了10次构造函数经过定位new的处理d1和p所代表的空间已经被重新初始化了。3、定位new的使用场景一般不会像上边代码一样对一块已有对象数据的空间重新初始化。定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化对于自定义类型的对象可以使用定位new对这些没有被初始化的内存显式调用类的构造函数初始化。五、泛型编程泛型编程编写与类型无关的通用代码是代码复用的一种手段。模板是泛型编程的基础。模板分为函数模板和类模板六、函数模板1、函数模板的使用123456789101112131415templatetypenameTvoidSwap(T a, T b){T tmp a;a b;b tmp;}intmain(){inta 10, b 5;doublem 2.3, n 4.9;Swap(a, b);Swap(m, n);return0;}两个Swap调用的不是模板而是模板生成的实例化函数像上述代码中模板会生成int和double类型的两种实例化函数。2、不同类型形参传参时的处理2.1传参时强转对应形参需要const修饰123456789101112templatetypenameTT Add(constT a,constT b)//const接收常性实参{returna b;}intmain(){inta 10, b 5;doublem 2.3, n 4.9;Add(a, (int)m);//强转临时变量传参具有常性return0;}使用强制类型转换在推演的时候将形参转换成同一类型。2.2显式实例化传参时隐式类型转对应形参需要const修饰123456789101112templatetypenameTT Add(constT a,constT b)//需要使用const接收{returna b;}intmain(){inta 10, b 5;doublem 2.3, n 4.9;Addint(a, m);//显式实例化m发生隐式类型转换return0;}显式实例化编译器不再去推演T的类型而是直接使用尖括号内的类型实例化对应函数。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2566761.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!