怎么让网站快速收录,沈阳建信建设工程有限公司,黄山学院教务管理系统,wordpress添加html菜单目录 简单回顾C语言动态内存管理
new、delete的用法
内置类型
new
delete
自定义类型
new、delete底层讲解#xff08;重要#xff09;
operator new 与 operator delete
定位 new
结语 简单回顾C语言动态内存管理
在C语言的学习阶段
我们接触到了三个能在堆上开辟…目录 简单回顾C语言动态内存管理
new、delete的用法
内置类型
new
delete
自定义类型
new、delete底层讲解重要
operator new 与 operator delete
定位 new
结语 简单回顾C语言动态内存管理
在C语言的学习阶段
我们接触到了三个能在堆上开辟空间的函数——malloc、calloc、realloc
其中malloc是开辟空间但是不初始化calloc是开辟空间并且会将空间内容都初始化为0而realloc则主要用于扩容如果传入的指针为空则效果和malloc一致
realloc又分为原地扩容和异地扩容
原地扩容就是扩容后的空间直接在原空间上往后延申但有一个前提就是在后扩展这段空间里面不能存在数据阻挡否则就会变成异地扩
异地扩容就是原空间后面有被使用的空间导致无法直接原地扩容就需要另外开辟一块完整空间最后再将数据拷贝到新空间原空间销毁
但是在C就不一样了C中的new会更为简洁各位看官且往下看 new、delete的用法
内置类型
new
我们在C如果要使用C语言中的malloc、calloc、realloc也是可以的因为C兼容C语言
但是日常没有人会这么用因为有更好的选择——new
我们在C中如果想要动态开辟一个空间可以选择直接new如下
int main()
{//动态开辟一块空间int* ptr new int;return 0;
}
如果我们要连续开辟一段空间呢比如开辟10个如下
int main()
{//动态开辟一块空间int* ptr1 new int;//动态开辟一段空间int* ptr2 new int[10];return 0;
}
那如果我想要开辟了空间之后进行初始化呢也是可以的我们先来看单单开辟了一个空间的情况
int main()
{//动态开辟一块空间并初始化int* ptr1 new int(5);return 0;
}
接着我们再来看一看一段空间的情况
int main()
{//动态开辟一段空间并初始化int* ptr2 new int[10] {1, 2, 3, 4, 5, 6};return 0;
}
如上我们会看到我们开辟了一段空间如果要初始化的话后面就需要跟上花括号{}而如上代码我们只输入了6个数字这也就代表着我们对应的初始化了前六个而后面剩下的四个则会默认初始化为0 delete
同样的C语言中清除空间有free在C中对应有delete如下展示几个例子
int main()
{//动态开辟一块空间int* ptr1 new int;delete ptr1;//动态开辟一块空间并初始化int* ptr2 new int(5);delete ptr2;//动态开辟一段空间int* ptr3 new int[10];delete[] ptr3;//动态开辟一段空间并初始化int* ptr4 new int[10] {1, 2, 3, 4, 5, 6};delete[] ptr4;return 0;
}
如上我们可以看到C中的delete一共有俩种用法——delete、delete[] 当只有单独一个空间的时候就使用delete 当有一段空间的时候就使用delete[] 当然这也比较好记因为这也和new一一对应 如上都是针对内置类型的情况但其实祖师爷搞出这块儿主要针对的是自定义类型 自定义类型
我们先来写一个类在该类的构造函数和析构函数里面分别打印一些内容方便我们检查结果
struct A
{A(){cout A() ;}~A(){cout ~A() ;}
};
然后我们再使用我们的new
int main()
{A* a1 new A;delete a1;cout endl endl;A* a2 new A[10];cout endl;delete[] a2;return 0;
} 我们可以看到当我们使用了new来开辟一块A类型的空间的时候他会在开辟空间的同时还会调用对应的构造函数
如果是开辟了一段空间比如10个的话就会连续调用10次构造函数并开辟对应大小的空间
而我们的delete就相反他会调用对应的析构如果是连续的就连续调用多次析构并销毁相应空间 new、delete底层讲解重要
operator new 与 operator delete
operator new 和 operator delete对标的是malloc和free
也就是说这个就是开辟空间的如果我们去看源码的话我们会发现operator new 其实就是对malloc的一个封装operator new 的底层就是mallocoperator delete同理
但是好好的为什么要对 malloc 封装呢直接用 malloc 不好吗
各位回想一下我们每次在使用完malloc之后都需要检查一下空间有没有开辟成功如果没有开辟成功我们还需要进行返回而且每写一个就需要检查一下写10个malloc就需要对应写10个检查这样子写得确实有点恼火
而在C语言种检查错误用的是错误码是errno
但是C使用了一种给更好的方法——异常这个知识太超纲了后面会重点学这里知道即可
所以本质上operator new 就是对 malloc 和异常进行了一个封装这也就使得C中的new变得异常简洁因为我们不需要检查直接使用new即可new里面有operator newoperator new 有malloc 和异常所以我们不需要检查
但是我们上面又看到开辟一个自定义类型的时候还会调用其构造函数
综上我们可以 得出一个结果 new operator new 构造函数 operator new malloc 异常错误检查 相对的delete也是大差不差但是operator delete可没有异常祖师爷在这块设计成这样单纯是为了对称所以 delete operator delete 析构函数 operator delete free 同理再来看看 new[]其本质就是多次调用operator new和构造仅此而已delete[] 同理
也就是在内部会多开四个字节用来记录连续开了几块空间再根据这四个字节里面的内容来决定到底要调用几次构造几次析构简图如以下假设连续开辟10个空间 定位 new
一般情况下我们会使用new而new会自动调用构造函数
但是我们会遇到一个情况这个情况出现在内存池中我们如果频繁地申请空间会使效率变低所以就有了内存池要申请先申请一大块空间需要申请就到内存池中申请内存池空间不够了再到堆里面去 但是我们如果要在内存池中申请空间的话就不能使用new因为new默认会调用堆上面的空间所以我们只能使用operator new但是我们这时候需要在类外面调用构造可是析构能在类外面显式调用但是构造不行所以就有了定位new的产生 定位new的语法有点子奇怪 new (place_address) type或者new (place_address) type(initializer-list) 举个例子
A* ptr (A*)operator new(sizeof(A));
new(ptr)A(10); //定位newptr-~A();
operator delete(ptr);
如上这是只申请一块空间的情况但如果是operator new[]的话就应该写一个for循环循环的次数就是需要调用构造函数的次数
A* ptr (A*)operator new(sizeof(A) * 10);
for(int i 0; i 10; i)new(ptri)A(5); //定位newfor(int i 0; i 10; i)(ptri)-~A();
operator delete[](ptr); 结语
这篇博客详细讲解了C中的动态内存管理如果觉得对你有帮助的话希望可以多多支持❀