C++动态内存管理
来源:互联网 发布:网络接入服务商怎么查 编辑:程序博客网 时间:2024/05/21 21:01
一、知识回顾:
1、C语言中使用malloc/calloc/realloc/free进行动态内存管理。
其中malloc与calloc区别是:malloc开辟空间时没有初始化,calloc开辟空间时初始化为0。
realloc一般用于扩容,包含两个参数(指针,容量大小),当指针为空时,等同于malloc;当指针不为空时:1)当指针后的空间大于等于要开辟的空间时,接着原来的空间开辟;2)当指针后的空间小于要开辟的空间时,重新开辟一块空间(该空间=原来空间大小+需要开辟空间的大小),并将原来空间的内容拷贝进去。
void Test(){int *p1=(int *)malloc(sizeof(int));free(p1);int *p2=(int *)calloc(4,sizeof(int));int *p3=(int *)realloc(p2,sizeof(int)*6);free(p3);
上面的代码不用对p2进行free(),因为把p2给了p3,释放掉p3即可。
2、C++*通过new和delete动态管理内存。*
new/delete动态管理对象;new[]/delete[]动态管理对象数组。
void Test(){ int *p4=new int;//动态分配4个字节(1个int)的空间,单个数据 int *p5=new int(3);//动态分配4个字节(1个int)的空间并初始化为3 int *p6=new int[3];//动态分配12个字节(3个int)的空间 delete p4; delete p5; delete[] p6;}
注:malloc/free、new/delete、new[]/delete[]一定要匹配使用,否则可能出现内存泄漏甚至崩溃的问题。
3、内存管理:
int globalVar=1; static int staticGlbalVar=1; void Test() { //1)全局变量、全局静态变量、局部静态变量、局部变量之间的区别是什么? static int ststicVar=1; int localVar=1;//2)下面的a1和a2和a3有什么区别和联系?int a1[10]={1,2,3,4};char a2[]="abcd";char* a3[]="abcd";}
解释:
1)局部变量存储于栈中;全局变量、全局静态变量和局部静态变量存储于静态区(数据段),其中全局静态变量和全局变量生命周期一样,区别是:链接属性不同,全局静态变量保持只在当前文件可见;局部变量和局部静态变量存储区不同,生命周期不同。
2)a1是静态变量,存储于栈中;a2是字符串常量,存储于常量区(代码段);a3是地址常量,存储于常量区。
注:
1>栈又叫堆栈,非静态局部变量/函数参数/返回值等等,栈是向下增长的。
2>内存映射段是高效I/O映射方式,用于装载一个共享的动态内存库。用户可使用系统接口创建共享共享内存,做进程间通信。
3>堆用于程序运行时动态内存分配,堆是向上增长的。
4>数据段——即静态区,存储全局数据和静态数据。
5>代码段——即常量区,存储可执行的代码/只读常量。
4、警告:动态内存分配相关的三种程序错误:
1)删除(delete)指向动态内存分配内存的指针失败,因而无法将该块内存返还给自由存储区。删除动态分配内存失败称为“内存泄漏”。
2)读写已删除的对象。如果删除指针所指的对象后,将指针置为0值,则比较容易检测这类错误。
3)对同一个内存空间使用两次delete表达式。当两个指针指向同一个动态创建的对象,删除时就会发生错误。
二、知识总结
1:总结并剖析malloc/free和new/delete之间关系和差异。
1)malloc/free和new/delete都是动态管理内存的入口。
2)malloc/free是C/C++标准库的函数,new/delete是C++操作符。
3)malloc/free只是动态分配内存空间/释放内存空空间;而new/delete除了分配空间还会调用构造函数和析构函数进行初始化与清理(清理成员)。
4)malloc/free需要手动计算类型大小,且返回值为void*,new/delete可以自己计算类型的大小,返回对应类型的指针。
class Array{public: Array(size_t size=10) :_size(size) ,_a(0) { cout<<"Array(size_t size)"<<endl; if(_size>0) { _a=new int[size]; } } ~Array() { cout<<"~Array()"<<endl; if(a) { delete[] _a; _a=0; _size=0; } }private: int* _a; size_t _size;}void Test(){ Array* p1=(Array*)malloc(sizeof(Array)); Array* p2=new Array; Array* p1=new Array(20); Array* p1=new Array[10]; free(p1); delete p2; delete p3; delete[] p4;}
注:new对于内置类型与malloc作用等同,但对于自定义类型,new开辟空间,且调用构造函数初始化,调用析构函数清理。
2:剖析new/delete、new[]/delete[]到底做了些什么事情。
1)C++的其他内存管理接口
void* operator new(size_t size)
void operator delete(size_t size)
void* operator new[](size_t size)
void operator delete(size_t size)
1>operator new/operator delete operator new[]/operator delete[]和malloc/free用法一样,区别是:开辟动态内存不成功时抛异常,而malloc返回0。
2>operator new/operator delete operator new[]/operator delete[]只负责分配空间/释放空间,不会调用构造函数/析构函数来初始化、清理对象。
3>operator new/operator delete 实际只是malloc/free的一层封装。
2)new、delete、new[]、delete[]
new做了两件事:
a)调用了operator new分配空间
b)调用了构造函数初始化对象
delete做了两件事:
a)调用析构函数清理对象
b)调用operator delete释放空间
new[]:
a)调用了operator new分配空间
b)调用了N次构造函数初始化N个对象
delete[]:
a)调用N次析构函数清理对象
b)调用operator delete释放空间
3)定位new表达式(replacement版本)
定位new表达式是在已分配的原始内存空间中调用构造函数初始化一个对象。
new(pleace_address)type
new(pleace_address)type(initializer-list)
pleace_address必须是一个指针,initializer-list是类型的初始化列表。
class Array{ public: Array(size_t size=10) :_size(size) ,_a(0) { cout<<"Array(size_t size)"<<endl; if(_size>0) { _a=new int [size]; } } ~Array() { cout<<"~Array()"<<endl; if(_a) { delete[] _a; _a=0; _size=0; } }private: int* _a; size_t _size;}void Test(){ //1.malloc/free+定位操作符new()/显示调用析构函数,模拟new和delete Array* p1=(Array*)malloc(sizeof(Array)); new(p1)Array(100); p1->~Array(); free(p1); //2.malloc/free+多次调用定位操作符new()/显示调用析构函数,模拟new[]和delete[] Array* p2=(Array*)malloc(sizeof(Array)*10); for(int i=0;i<10;++i) { new(p2+i)Array; } for(int i=0;i<10;++i) { p2[i].~Array(); } free(p2);}
注意:分析delete[]的对象是自定义类型时,是怎么知道要调用N次析构函数的?
解析:当用自定义类型,显示定义析构函数并调用时,会在头部开4或8字节空间存储对象个数N,方便析构时知道调用析构多少次。
当使用new[]开辟10个对象的空间时,如下图:
如果接着选用deltete[]时,会同时清理释放多开的空间;而如果选用deltete,多开的空间未释放,存在内存泄漏,程序会崩。
故而:
当没有显示定义析构函数时,new、new[]与delete、delete[]随便匹配,程序不会崩;因为没有显示定义析构函数,编译器对调用默认析构函数这一步进行了优化,程序也不会崩。当显示定义析构函数时,new、new[]与delete、delete[]必须匹配。
3:实现NEW_ARRAY/DELETE_ARRAY宏,模拟new[]/delete[]申请和释放数组。
//模拟new[]#define NEW_ARRAY(ptr,type,n)do{ //1.开空间,使用operator new,同时开出4个字节存储个数 ptr=operator new(sizeof(type)*n+4); *((int *)ptr)=n; ptr=(type*)((char*)ptr+4);//指针调过用于存储个数的空间 //2.初始化,使用定位操作符new() for(int size_t=0;i<n;++i) { new(ptr+i)type; } }while(0); //模拟delete[] #define DELETE_ARRAY(ptr,type) do { //获得需要调析构函数的个数n,并调用n次析构函数 size_t n=*((int *)ptr-1); for(int size_t=0;i<n;++i) { ptr[i].~type(); } //释放空间,调用operator delete operator delete((char *)ptr-4)); }while(0);
- 【C++】动态内存管理
- 【C++】动态内存管理
- 【C++】动态内存管理
- C语言动态内存管理
- c的动态内存管理
- C语言动态内存管理
- C语言动态内存管理
- C/C++动态内存管理
- C语言动态内存管理
- 【C++】C++动态内存管理
- C/C++动态内存管理
- c的动态内存管理
- C/C++动态内存管理
- c/c++动态内存管理
- C/C++动态内存管理
- C/C++动态内存管理
- C/C++动态内存管理
- C/C++动态内存管理
- HDU-1875 畅通工程再续 (prim)
- dll注入到进程(C++)
- Java验证IP地址是否属于指定局域网网段
- 写出这个数 (20)
- 迪杰斯特拉算法的实现
- C++动态内存管理
- Android蓝牙通讯(二)————蓝牙的相关操作
- Maven的总结I
- ccf/公共钥匙盒
- 9. Palindrome Number(数学)
- xUbuntu16.04_64+python2.7+anaconda2+pycharm配置
- 30分钟掌握ES6/ES2015核心内容(上)
- hive 创建表时遇到问题 Failed to recognize predicate 'xxx'. Failed rule: 'identifier' in column specificat
- Struts2_001_使用 Filter 作为控制器的 MVC