🏳️🌈C/C++内存分布
说明:
1.我们的代码并非放在代码段里的,而是以文件的形式存在磁盘上的。
代码经过编译链接形成的二进制指令,才是放进代码段里的。(即可执行代码)
2.“abcd”如果没有被const修饰,那是放在栈区的。经过const修饰为只读常量后,放在代码段。
练习:
int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = { 1, 2, 3, 4 };
char char2[] = "abcd";
const char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
free(ptr1);
free(ptr3);
}
(选择题) 选项: A.栈 B.堆 C.数据段(静态区) D.代码段(常量区)
globalVar在哪里?
staticGlobalVar在哪里?
staticVar在哪里?
localVar在哪里?
num1 在哪里?
char2在哪里?
*char2在哪里?
pChar3在哪里?
*pChar3在哪里?
ptr1在哪里?
*ptr1在哪里?
答案:
CCCAA
AAADAB
🏳️🌈C++的内存管理方式
new/delete
C++在原有基础上(malloc之流) 引入了new和delete。
new的用法:
//动态申请一个int类型的空间
int*p1 = new int;
//动态申请一个int类型的空间,并初始化为10
int*p2 = new int(10);
//动态申请10个int类型的空间
int*p3 = new int[10];
//动态申请10个int类型的空间,并将前三个分别初始化为1、2、3
int*p = new int[5]{1,2,3}; //注意:这种方式C++98是不支持的,C++11支持
delete的用法:
delete p1;
delete p2;
delete[] p3;
//注:下面这种写法是错误的
delete p1,p2; //这样写仅能delete p1
delete是一个操作符,后面直接跟操作数,不需要像free那样接 ( )。
之前C语言中学到的malloc、calloc、free等,C++中照样是可以用的。
❓那么问题来了:new/delete 和 malloc/free 的区别是什么?
区别一:在对待自定义类型上
📖其实两者对待内置类型没有区别。
但是对于自定义类型,new /delete 除了开空间还会调用构造函数和析构函数。
可见,new/delete是为自定义类型准备的。
区别二:开辟失败时
malloc申请空间失败会返回NULL,所以需要进行检查
而new申请不需要做检查,因为申请失败它直接抛异常:
通过try-catch可以知道发生了什么异常:
结果:bad allocation
区别三:new/delete是关键字,而malloc/free是函数
new/delete操作自定义类型
class A
{
public:
A() {
cout << "A()" << endl;
}
~A() {
cout << "~A()" << endl;
}
};
int main()
{
A* p1 = new A; //new自定义类型
delete p1;
A* p2 = (A*)malloc(sizeof(A)); //malloc自定义类型
free(p2);
int* p3 = new int; //new内置类型
delete p3;
int* p4 = (int*)malloc(sizeof(int)); //malloc内置类型
free(p4);
return 0;
}
结果:
可见,只有new/delete在操作自定义类型时,会自动调用构造和析构函数。
new/delete的底层原理
new/delete的底层原理其实是 调用了函数operator new / operator delete来申请和释放空间。
注:这里不是运算符重载,函数名就是operator new。
👁️🗨️我们来看一下函数operator new :
void *__CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
void *p;
while ((p = malloc(size)) == 0) //通过malloc申请
if (_callnewh(size) == 0)
{
// 当内存不够,申请失败时
// 这里会抛出bad_alloc 类型异常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return (p);
}
可见,operator new 实际也是通过malloc来申请空间,而operator delete是通过free来释放空间的。
既然本质还是用malloc,那兜这么一圈的意义何在?
开空间的同时封装了malloc,失败时能符合C++new的失败机制,即抛异常。