c++动态内存管理相关知识
1.c语言动态内存管理
c语言使用malloc、calloc、realloc、free进行动态内存管理
Void test()
{
int* p1 = (int*)malloc(size(int)*4);
int* p2 = (int*)calloc(4,sizeof(int));
int* p3 = (int*)realloc(p2,sizeof(int)*6);
free(p1);
free(p2);
free(p3);
}
(1)malloc函数在内存的动态存储区中分配一块长度为size字节的连续区域,返回该区域的地址,不初始化。
(2)calloc函数与malloc函数相似,不同的是calloc会将所分配的空间中的每一位都初始化为零。
(3)realloc函数会首先判断oldbase后是否有足够要求的新空间,若有,则扩大oldbase指向的地址空间;若没有,就重新另外分配一块地址空间,并将原有的数据拷贝到新的空间,然后释放原有的内存空间,同时返回新分配的内存空间首地址。
malloc、calloc、realloc必须和free匹配使用,否则可能出现内存泄露甚至崩溃的问题。
2.c++是兼容c的,而c语言库中已经有malloc/free等管理动态内存,为什么c++还要定义new/delete运算符来管理动态内存呢?
malloc/free和new/delete的区别与联系
(1)它们都是动态管理内存的入口;
(2)malloc/free是c/c++库中函数,new/delete是c++中的操作符;
(3)malloc/free只是动态分配内存空间/释放空间,而new/delete不仅分配空间还调用构造函数和析构函数进行初始化和清理(清理成员);
(4)malloc/free需要手动计算类型大小且返回值为void*,new/delete可自动计算类型大小且返回的是对应类型的指针。
因此引入c++动态内存管理new/delete操作符。
3.c++动态内存管理基本语法和使用
new/delete动态管理对象
new[]/delete[]动态管理对象数组
void test()
{
int* p1 = new int;//动态分配4个字节(1个int)的空间单个数据
int* p2 = new int(3);//动态分配4个字节(1个int)的空间并初始化为3
int* p3 = new int[3];//动态分配12个字节(3个int)的空间
delete p1;
delete p2;
delete [] p3;
}
new/delete和new[]/delete[]必须匹配使用,否则可能出现内存泄露甚至崩溃的问题。
(1)new/operator底层实现
#include<iostream>
//#include<cstdlib>
using namespace std;
class Array
{
public:
Array(size_t size = 5)
:_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* p3 =new Array(20);
Array* p4 =new Array[10];
free(p1);
delete p2;
delete p3;
delete[] p4;
}
int main()
{
Test();
system("pause");
return 0;
}
调试转到反汇编可以看到,new调用了operator new开辟空间
然后调用构造函数初始化
delete、delete[]调用析构函数清理对象,然后调用operator delete、operator delete[]释放空间。
(2)void* operator new (size_t size);
void operator new (void* p);
void* operator new (size_t size);
void operator new (void* p);
operator new/operator delete,operator new[]/operator delete[]和malloc/free用法一样。
他们只负责分配空间/释放空间,不会调用对象构造函数/析构函数来初始化/清理对象。
实际operator new和operator delete只是malloc和free的一层封装。
注意:
operator new()/operator delete()是c++的标准库函数,而不是运算符的重载。
(3)new[N]
*.调用operator new分配空间;
*.调用N次构造函数分别初始化每个对象。
Delete[]
*.调用N次析构函数清理对象;(思考N是如何而来?)
*.调用operator delete释放空间。
根据以上代码中的
Array* p4 =new Array[10];
delete[] p4;
得 这两条语句实际是调用operator new[](10*sizeof(Array)+4)分配大小为10*sizeof(Array)+4空间,其中多的四个字节空间用于存放delete中调用析构函数的次数,空间申请好后调用构造函数创建对象。
delete[] p4执行时首先取N个对象个数,然后调用析构函数析构对象,最后用operator delete[]函数释放空间。
总结:new在开辟内置类型空间时,开辟的空间数量是指定的空间数量,字节数是指定的数量乘以类型的大小;当为非内置类型开辟空间,并且该类有自定义的析构函数时,才会多出4个字节。
(4)定位new表达式
在已分配的原始内存空间中的特定位置处调用构造函数初始化一个对象。
模拟实现new表达式
模拟实现DELETE