c++内存管理:
创始人
2024-01-16 20:12:34
0

目录

new和delete

使用方法:

注意事项:

new申请不需要检查返回值

operator new和operator delete函数的讲解


c语言申请内存有哪些方法:

答:malloc  calloc realloc三种

#include
void test()
{int*p1 = (int*)malloc(sizeof(int));free(p1);int*p2 = (int*)calloc(4, sizeof(int));int *p3 = (int*)realloc(p2, sizeof(int)* 10);free(p3);
}

其中,malloc就是普通的动态内存申请

calloc相当于malloc加上memset把申请的空间全部初始化为0

realloc相当于内存扩容,分为异地扩容和原地扩容,当扩容的次数少,空间小时,会执行原地扩容,当扩容的次数多,空间大时,会执行异地扩容。

原地扩容和异地扩容的区别?

答:如上图代码所示,p2和p3指针指向同一块空间,而异地扩容则不然,异地扩容会先找一块新的空间,然后把原空间的内容拷贝到新空间位置,然后释放掉原空间,所以返回的就是p3.

new和delete

使用方法:

c++是通过什么申请内存的呢?

答:c++是通过两个关键字(操作符)来申请和释放空间的。

new和delete

int main()
{int *p1 = new int;delete p1;return 0;
}

相当于这里申请一个字节的空间,返回指向该空间的指针p1,然后delete表示释放空间。

注意:这里申请空间并不会对空间上的内容完成初始化:

例如:

 我们申请的空间并没有进行初始化。

我们如何申请空间的同时并初始化呢?

答:我们可以这样操作

例如:

int main()
{int *p1 = new int(0);delete p1;return 0;
}

 我们在后面加上0表示申请空间并把空间初始化为0.

我们如何申请多个空间呢?

答:

int main()
{int *p1 = new int[10];delete[] p1;return 0;
}

这里表示我们要申请十个整型空间,注意:我们在delete释放时,要和我们申请的空间进行一一对应。

 假如我们要对申请的多个空间进行初始化呢?

答:我们可以这样写:

int main()
{int *p1 = new int[10]{1, 2, 3, 4};delete[] p1;return 0;
}

这里表示我们对申请的十个空间中的前4个进行初始化:

 我们发现,对于内置类型,这里的new和delete和c语言的动态内存申请函数本质上没什么区别,那为什么++要定义这两个关键字呢?

答:对于内置类型,c语言和c++的动态内存申请本质是一样的,但是对于自定义类型,结果就不同了

例如:

我们写一个简单的类:

class A
{A(int a = 0):_a(a){cout << "A():" << this << endl;}~A(){cout << "~A():" << this << endl;}
private:int _a;
};

这个类中有两个成员函数,分别是构造函数和析构函数,函数的目的是当调用构造和析构函数,打印对应的提示并打印出this指针。

我们进行实验:

int main()
{/*int *p1 = new int[10]{1, 2, 3, 4};delete[] p1;return 0;*/A* p1 = new A;}

我们动态内存申请一个类的空间,返回指向该空间的指针p1

我们进行编译:

 这里表示我们的动态内存申请new调用了构造函数。

但是我们的malloc是不会调用构造函数的:

int main()
{/*int *p1 = new int[10]{1, 2, 3, 4};delete[] p1;return 0;*//*A* p1 = new A;*/A*p1 = (A*)malloc(sizeof(A));
}

我们进行编译:

 所以new相较于malloc对于自定义类型来说,new会调用自定义类型的构造函数,而malloc不会。

new会调用自定义类型的构造函数,那么delete是不是也会调用析构函数?

答:会:

int main()
{/*int *p1 = new int[10]{1, 2, 3, 4};delete[] p1;return 0;*/A* p1 = new A;/*A*p1 = (A*)malloc(sizeof(A));*/delete p1;
}

我们进行调用:

 所以delete也会调用自定义类型的析构函数。

我们举一个之前写的链表的例子:

struct ListNode
{ListNode(int val = 0):_next(nullptr), _val(val){}ListNode* _next;int _val;
};

我们现在可以这样写链表:

struct和class都是类关键字,struct当我们不处理时,类中的成员的默认用public修饰。

我们可以在类中写构造函数,相当于我们之前的创建新节点

int main()
{ListNode*n1 = new ListNode(1);ListNode*n2 = new ListNode(2);ListNode*n3 = new ListNode(3);ListNode*n4 = new ListNode(4);n1->_next = n2;
}

这样写链表就会方便很多。

注意事项:

注意:

new和delete一定要匹配,否则会产生意想不到的问题,我们就只举一个例子:

例如:

nt main()
{A*p1 = new A[10];delete p1;
}

我们写出这样的代码进行运行就会报错:

为什么会这样呢?

我们先写一个正常的进行分析:

 

int main()
{A*p1 = new A[10];delete[] p1;
}

我们的A的成员只有一个整型,所以A占四个字节的空间,十个A就占40个字节的空间。

 我们先进行编译:

 我们进行申请时或进行释放时,都会调用多次调用构造函数或析构函数。

我们在创建时,知道我们需要创建十个A类所占的空间

但是我们在析构的时候,并不清楚我们需要析构多少次,这时候,我们需要额外申请一个整型的空间:

 接下来,我们把p1往前置:

 这时候,我们就知道我们需要析构多少次,并且从这里可以把我们申请的空间全部释放。

我们返回来看之前报错的情况:

 

int main()
{A*p1 = new A[10];delete p1;
}

为什么会报错呢?

答: 因为我们释放没有写[],所以我们构造了十次,但是我们不清楚析构了多少次,所以就会报错。

上面的这些都是关于编译器vs2013的一些情况,举这些例子只是为了说明一定要把申请的空间和delete释放的空间进行对应

new申请不需要检查返回值

我们知道malloc申请大的空间或者连续申请小的空间就会报错:

int main()
{while (1){int *p1 = (int*)malloc(1024 * 1024);if (p1){cout << p1 << endl;}else{cout << "申请失败" << endl;break;}}
}

并且我们知道,当malloc申请失败的时候,会返回空指针,所以我们可以写出以上代码来进行实验:

 

 申请多次的时候,报错

接下来,我们对new进行实验:

int main()
{while (1){int *p1 = new int[1024 * 1024];if (p1){cout << p1 << endl;}else{cout << "申请失败" << endl;break;}}
}

 运行很快就停止了,但是并没有打印出申请失败,说明我们new失败的返回值并不是0,或者说,new失败没有返回值。

new失败的话,就会抛异常,所以我们不需要对返回值进行检查,对于抛异常的问题,我们之后再进行详解。

operator new和operator delete函数的讲解

上述的两个函数是new和delete的底层实现:

 new的底层实现就是通过new调用operator new函数,operator函数中有malloc,调用完毕之后调用构造函数。

注意:operator new函数并不是new的重载。

operator new相当于是一个新的全局函数。

我们看一下operator函数的定义:

 我们可以发现,operator new函数就是malloc函数的封装,无非就是加上了当申请失败时,不反回,而是抛异常。

我们观察一下operator delete函数。

 相当于我们operator的主体部分也是调用了free函数。

我们是否可以使用operator new来申请空间呢?

答:可以:

例如:

int main()
{while (1){char*p1 = (char*)operator new(1024 * 1024 * 1024);cout << (void*)p1 << endl;}
}

operator new的使用方法和malloc相似。

不同点在于:operator new申请失败的话不需要报错,因为会抛异常。

相关内容

热门资讯

教师节的征文 教师节的征文精选  在学习、工作或生活中,大家都有写征文的经历,对征文很是熟悉吧,征文是某个办事部门...
暑假旅游记事作文 暑假旅游记事作文  说起这个暑假呀,我真是太开心了,给大家讲一讲话暑假的开心事吧!  这个暑假,爸爸...
清明节小学作文 清明节小学作文15篇  在平日的学习、工作和生活里,大家对作文都再熟悉不过了吧,作文是从内部言语向外...
玩转麦鲁小城作文600字 玩转麦鲁小城作文600字暑假里的一天,难得的阴凉天气,我在家中望着外面,看到清洁员忙忙碌碌,一个想法...
思念亲人作文 关于思念亲人作文(通用5篇)  在我们平凡的日常里,大家一定都接触过作文吧,借助作文可以宣泄心中的情...
历史经典成语故事 历史经典成语故事(精选16篇)  故事:在现实认知观的基础上,对其描写成非常态性现象。是文学体裁的一...
扬帆起航作文600字 扬帆起航作文600字(通用40篇)  在生活、工作和学习中,大家或多或少都会接触过作文吧,借助作文可...
勤俭节约作文600字 关于勤俭节约作文600字(通用54篇)  在日常生活或是工作学习中,大家最不陌生的就是作文了吧,借助...
我的六一儿童节作文500字 【热门】我的六一儿童节作文500字四篇  在现实生活或工作学习中,大家总免不了要接触或使用作文吧,作...
什么时候立冬 2021什么时候立冬  立冬是二十四节气之一,那么2021年立冬是什么时候呢?2021立冬节气又是哪...
端午节作文300字 端午节作文300字精选7篇  在日常学习、工作抑或是生活中,大家都接触过作文吧,作文是经过人的思想考...
粽子的来历与传说故事 粽子的来历与传说故事(通用7篇)  端午节马上要来了,说到端午节小编想到的就是粽子了,中国饮食文化是...
国庆趣事作文400字 国庆趣事作文400字(精选38篇)  在平日的学习、工作和生活里,许多人都有过写作文的经历,对作文都...
植树节的作文700字 【热门】植树节的作文700字汇编9篇  在日常学习、工作或生活中,许多人都有过写作文的经历,对作文都...
小学三年级作文 小学三年级作文(通用48篇)  在教学工作者开展教学活动前,通常会被要求编写,是备课向课堂教学转化的...
我的十一假期作文300字 我的十一假期作文300字  这个假期爸爸妈妈都很忙,但还是抽出了一天的时间和我去植物园。  清晨,我...
小学作文牵牛花 小学作文牵牛花  1牵牛花  每天早上,我在上学的路上,总看见一种花,在围墙上生长——牵牛花,又叫喇...
做手工作文 做手工作文做手工“六一”儿童节学校要举行“手工比一比”所以每个同学都要自己动手做。今天妈妈要准备把手...
春雨 春雨  “轰隆隆”一声闷雷,一阵春雨随之而来,这预示着美好的春天终于降临了。    “好雨知时节,当...
小猫吃鱼作文 小猫吃鱼作文(15篇)  在日常学习、工作和生活中,大家或多或少都会接触过作文吧,借助作文可以宣泄心...