在学习相关内容之前,我们先来做一道题目:

分析: globalvar是一个全局变量,所以globalvar在静态区;static GlobalVar被static修饰,说明它是一个静态变量,那就在静态区;static Var在静态区;localVar是一个局部变量,局部变量的空间都是在桟帧中开辟的,所以在栈上;num1单独出现,表示数组首元素的地址,那它就是一个指针变量,在栈上;char2表示数组名,为首元素地址,字符串存储在数组中,这个字符串是可以被修改的,那么这个字符串就是在栈上,那char2就在栈上;*char2表示首元素,也在栈上;pchar3是一个指针变量,在栈上;const char* pchar3="abcd"中的const修饰的是指针指向的内容,这个内容不能被修改,这个字符串为常量字符串,在常量区,*pchar3就在常量区;ptr1中存放的是申请空间的地址,是一个指针变量,在栈上;*ptr1表示申请空间的首元素,空间是在堆上申请的,所以*ptr1在堆上。
选择题答案
globalVar在哪里?______ C. 数据段(静态区)
staticGlobalVar在哪里?______ C. 数据段(静态区)
staticVar在哪里?______ C. 数据段(静态区)
localVar在哪里?______ A. 栈
num1 在哪里?______ A. 栈
char2在哪里?______ A. 栈
*char2在哪里?______ A. 栈
pChar3在哪里?______ A. 栈
*pChar3在哪里?______ D. 代码段(常量区)
ptr1在哪里?______ A. 栈
*ptr1在哪里?______ B. 堆
图示解释:


回顾前面在C语言中的学习,我们学习过malloc/calloc/realloc/free,我们通过题目来回顾一下:

【面试题】
1. malloc/calloc/realloc的区别?
malloc申请空间时不进行初始化,calloc申请空间时自动初始化为0;realloc是对空间的增容:如果原空间后面有空间,那直接在其后面直接扩容,新空间的地址和原空间的地址一样;如果原空间的后面空间不够,则新找一块空间,并将原空间中的数据拷贝到新空间中,再将原空间释放,然后返回新空间的地址
2. malloc的实现原理? glibc中malloc实现原理
其实C语言中的内存管理已经可以解决很多问题,那为什么C++中要搞个新的内存管理呢?ok,通过下面的学习,我们就知道原因了:
C语言内存管理方式在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式——通过new和delete操作符进行动态内存管理。



那这时候就有人想问了,如果我们想要初始化,该怎么做?

delete的使用分为两种情况: 情况1:释放单个
//申请一个int类型的空间,并初始化
int* p3 = new int(10);
//释放单个
delete p3;情况2:释放多个
//申请一个空间大小为10的数组,int类型,并部分初始化
int* p4 = new int[10] {1, 2, 3, 4};
//释放多个
delete[] p4;提醒: 释放多个也可以直接写delete p4; 但是不建议这么写
这里博主有一个问题:我们看啊,在C中有申请空间,还有扩容,刚才我们学习C++中的申请空间,那C++中有扩容吗?
其实是没有的,如果需要扩容,自己手动扩
我们看到其实new和delete的功能和malloc、calloc、free的功能很接近,那为什么祖师爷还要搞new和dlete呢?
其实是为了自定义类型,用malloc可以申请一个自定义类型的空间,那该怎么初始化呢?这是不是一个问题,那为了解决这个问题,祖师爷就搞出了new和delete

new和delete就可以解决这样的问题!!!

我们看到:new和delete的最大特点就是自动调用构造和析构,而malloc和free不会!!!以后主要使用new和delete
new 和 delete也会失败,那他们的失败和malloc free的失败是一样的吗?
其实是不一样的,new申请空间失败不会返回空,而是会抛异常

那我们该怎么捕获异常呢(ok,这里博主简单演示一下,后面会具体介绍):
void func()
{
int i = 1;
int* ptr = nullptr;
do {
if (i == 495)
{
int x = 0;
}
ptr = new int[1024 * 1024];
cout << i++ << ":" << ptr << endl;
} while (ptr);
cout << i++ << ":" << ptr << endl;
}
int main()
{
try
{
func();
}
catch (const exception& e)
{
cout << e.what() << endl;
}
return 0;
}通过上面的try,catch就可以捕获异常。
new在底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间。operator new 和operator delete是系统提供的全局函数
new开空间的步骤:
先调用operaotr new 在堆上开空间(底层还是调用malloc)——这是什么意思?
我们来看一下底层代码:
void* __CRTDECL operator new(size_t size) _THROW1(_STD bad_alloc)
{
// try to allocate size bytes
void* p;
while ((p = malloc(size)) == 0)
if (_callnewh(size) == 0)
{
// report no memory
// 如果申请内存失败了,这里会抛出bad_alloc 类型异常
static const std::bad_alloc nomem;
_RAISE(nomem);
}
return(p);
}operator new:该函数实际通过malloc来申请空间,当malloc申请空间成功时直接返回;申请空间失败,尝试执行空 间不足应对措施,如果改应对措施用户设置了,则继续申请,否则抛异常。
所以说new的底层还是调用malloc,可以认为new是对malloc的包装
delete的步骤:
void operator delete(void* pUserData)
{
_CrtMemBlockHeader* pHead;
RTCCALLBACK(_RTC_Free_hook, (pUserData, 0));
if (pUserData == NULL)
return;
_mlock(_HEAP_LOCK); /* block other threads */
__TRY
/* get a pointer to memory block header */
pHead = pHdr(pUserData);
/* verify block type */
_ASSERTE(_BLOCK_TYPE_IS_VALID(pHead->nBlockUse));
_free_dbg(pUserData, pHead->nBlockUse);
__FINALLY
_munlock(_HEAP_LOCK); /* release other threads */
__END_TRY_FINALLY
return;
} /
*
free的实现
* /
#define free(p) _free_dbg(p, _NORMAL_BLOCK)operator delete: 该函数最终是通过free来释放空间的!!!
通过上述两个全局函数的实现知道,operator new 实际也是通过malloc来申请空间,如果malloc申请空间成功就直接返回,否则执行用户提供的空间不足应对措施,如果用户提供该措施就继续申请,否则就抛异常。operator delete 最终是通过free来释放空间的。
new的原理
delete的原理
new T[N]的原理
delete[]的原理
malloc/free和new/delete的共同点是:都是从堆上申请空间,并且需要用户手动释放。不同的地方是:
上面的区别不建议背,理解即可!!!