👍作者主页:进击的1++
🤩 专栏链接:【1++的C++初阶】
文章目录
- 一,C/C++的内存分布
- 二,malloc,realloc,calloc的区别
- 三,C++的内存管理- -new和delete
- 初识new和delete
- new和delete操作自定义类型
- 深度剖析new与delete
- 定位new
- 四,new/delete与malloc/free的区别
一,C/C++的内存分布
如上图所示,C/C++程序在运行时占用的内存主要是这几部分
1. 栈:函数栈帧是建立在栈中的,所以在栈中会存储一些非静态局部变量,函数参数,返回值等。
2. 堆:我们动态申请的内存就在堆中。
3. 内存映射段:后面的文章会涉及,暂时不是很了解。
4. 数据段:全局变量,static修饰的变量,函数等。
5. 代码段:const修饰的只读常量,可执行程序等。
二,malloc,realloc,calloc的区别
我们首先来说他们各自的作用与用法:
- malloc:malloc是C语言中用来动态申请内存的函数,它能够申请所输入参数大小的空间,单位为字节,并且malloc的类型为void*,因此,在使用时要进行强制类型转换。
- calloc:calloc和malloc的功能差不多,区别就是,在申请内存的同时,能够将内存初始化为0。
- realloc:reallocation主要进行扩容,其有两种扩容方式,一是,在原来申请内存的后面扩容,二是,由于其后面的内存不够,另找一块地方,将原来申请内存中的内容拷贝到新的申请的内存中。
- 它们申请失败都会返回NULL,因此要加断言或判断语句来进行判断是否申请成功。
三,C++的内存管理- -new和delete
初识new和delete
我们来看以下代码:
void Test()
{
int* ptr1 = new int;//申请一个int类型的空间
int* ptr2 = new int[3]{1,2,3};//申请三个int类型的空间,并将其分别初始化为1,2,3
int* ptr3 = new int(10);//申请一个int类型的空间,并将其初始化为10
}
int main()
{
Test();
return 0;
}
其运行结果如下图:
以上就是new的几种用法,要注意的是,在第二种用法中,对开辟的空间要全部初始化,不能初始化部分。
再来看下面的代码:
void Test()
{
int* ptr1 = new int;
int* ptr2 = new int[3]{1,2,3};
int* ptr3 = new int(10);
delete ptr1;
//delete[] ptr2;
delete ptr2;
delete ptr3;
}
int main()
{
Test();
return 0;
}
运行结果如下:
通过上述结果,我们发现new 要与delete搭配,当要释放申请了多个对象的连续空间时,就必须用delete [] xxx来进行释放。
也就是new [] 要与delete [] 搭配。
new和delete操作自定义类型
我们来看下面这段代码:
class Date
{
public:
Date(int year = 2023, int month = 5, int day = 3)
:_year(year)
, _month(month)
, _day(day)
{
cout << "Date()" << endl;
}
~Date()
{
cout << "~Date()" << endl;
}
private:
int _year;
int _month;
int _day;
};
void Test2()
{
Date* p1 = (Date*)malloc(sizeof(Date));
Date* p2 = new Date(2022,5,18);
//Date* p3 = new Date[3];
free(p1);
delete p2;
//delete[] p3;
}
运行结果如下:
将p2屏蔽后:
通过观察上述两张运行结果图,我们发现,使用new和delete编译器会自己调用其构造与析构函数,而使用malloc与free则不会。而对于内置类型,则几乎没区别。
深度剖析new与delete
我们将上述代码的汇编指令调出来,如下图:
在图中我们可以清楚的观察到,new先是调用了operator new然后调用了其构造函数。delete也是类似先调用其析构,再调用operator delete。那么什么是operator new和opertaor delete呢?
operator new 和operator delete是系统提供的全局函数与前面所学的类重载的函数是不同的;new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。
operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空间不足应对措施,如果应对措施用户设置了,则继续申请,否则抛异常。malloc申请失败返回NULL,而new会抛异常。
operator delete: 该函数最终是通过free来释放空间的。
定位new
什么叫定位new?定位new就是已分配的原始内存空间中调用构造函数初始化一个对象。
定位new表达式在实际中一般是配合内存池使用。因为内存池分配出的内存没有初始化,所以如
果是自定义类型的对象,需要使用new的定义表达式进行显示调构造函数进行初始化。
定位new的简单使用如下代码:
void Test2()
{
Date* p1 = (Date*)malloc(sizeof(Date));
//Date* p2 = new Date(2022,5,18);
//Date* p3 = new Date[3];
new(p1)Date;//定位new显式调用构造函数
p1->~Date();//显式调用析构函数
free(p1);
//delete p2;
//delete[] p3;
}
运行结果如下:
四,new/delete与malloc/free的区别
- new delete是操作符而malloc,free是函数。
- new可以就行初始化而malloc不可以。
- 对于自定义类型new,delete会调用构造与析构函数,而malloc,free不会。
- new申请空间失败后会抛异常而malloc会返回NULL.
- new相较于malloc用起来更加方便。