C++动态内存开辟

个人简介

  • 作者简介:大家好,我是菀枯

  • 支持我:点赞+收藏⭐️+留言

  • 格言:不要在低谷沉沦自己,不要在高峰上放弃努力!☀️

    v2-af3cfbda99d44f8eb114cc6c74c92253_720w

    前言

在C语言时,我们学习了一些动态开辟内存的方式比如malloc, calloc, realloc等等,但是这些函数不太能满足C++的需求。比如一个自定义类型,如果用C语言的函数去开辟一个空间,创建完成后我们还需要手动去对块空间去进行初始化,这样就不太方便,于是C++创造出了new 和 delete。

内存分布

在学习如何去开辟一片空间之前,我们先来复习一下C语言中是如何划分内存空间的,在C语言中内存大致可以分为六个区域,自上而下分别为:内核空间,栈区,内存映射区,堆区,数据段,代码段

C++动态内存开辟_第1张图片

光说不练假把式,我们来看一个题目,来检验一下大家对于这块的知识还记得多少。

上代码。

int c = 1;
void Test() {
	static int a = 1;
	int b = 1;

	int num[10] = { 1,2,3,4 };
	char char1[] = "abcd";
	char* pchar2 = "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);
}

1.选择题

选项: A.栈 B.堆 C.数据段 D.代码段

a在哪里?____________ b在哪里?____________

c在哪里?____________ num1在哪里?____________

char1在哪里?____________ *char1在哪里?____________

pchar2在哪里?____________ *pchar2在哪里?____________

ptr1在哪里?____________ *ptr1在哪里?____________

2.填空题

sizeof(num) = ____________

sizeof(char1) = ____________ strlen(char1) = ____________

sizeof(pchar2) = ____________ strlen(pchar2) = ____________

sizeof(ptr1) = ____________

请大家仔细思考后,再看下方的答案。

C++动态内存开辟_第2张图片

1.选择题

选项: A.栈 B.堆 C.数据段 D.代码段

a在哪里? C b在哪里? A

c在哪里? C num1在哪里? A

char1在哪里?A *char1在哪里?A

pchar2在哪里?A *pchar2在哪里?C

ptr1在哪里?A *ptr1在哪里?B

2.填空题

sizeof(num) = 40

sizeof(char1) = 5 strlen(char1) = 4

sizeof(pchar2) = 4/8 strlen(pchar2) = 4

sizeof(ptr1) = 4/8

你答对了多少呢?C++动态内存开辟_第3张图片

C++内存管理方式

new和delete是C++中新引入的两个关键字,一个是用来开辟内存的,一个是用来释放内存的。

内置类型

int main() {
	//开辟一个int的空间
	int* p1 = new int;

	//开辟一个int的空间,并将值初始化为10
	int* p2 = new int(10);

	//开辟一个3个int的空间
	int* p3 = new int[3];

	delete p1;
	delete p2;
	delete[] p3;

	return 0;
}

new和delete的两种使用方式:

  1. 对于申请和释放单个空间,使用new和delete。

    书写方式:(类型*)变量名 = new 类型 (初始化的值),delete 变量名。

  2. 对于申请和释放多个空间,使用new[]和delete[]。

    书写方式:(类型*)变量名 = new 类型 [个数], delete[]变量名。

    多个空间无法使用()号在new后指定初始化的值,只可采取:

    int *p = new int[10]();
    

    将这一片空间初始化为0。

自定义类型

对于自定义类型,new和delete在使用上大体相似,只是开辟空间时回去调用自定义类型的构造函数,而销毁空间时会去调用自定义类型的析构函数。

new和delete

operator new 和 operator delete

​ 在C++中,new和delete是操作符,而operator new和operator delete是两个全局函数,new操作符是通过调用operator new来开辟空间的,delete操作符是通过调用operator delete来销毁空间的。

vs2013下operator new源码:

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);
}

抛异常是C++中一种处理程序问题的方式,我们以后会讲。大家可以看到源码中开辟内存是使用C语言中的malloc来开辟的空间,这就是为什么内置类型使用new和C语言中使用malloc开辟空间没什么区别的原因。

首先我们先来看看C语言中的free是什么:

#define free(p) _free_dbg(p, _NORMAL_BLOCK)

我们可以看到我们在C语言中使用的free,其实是一个宏,在程序编译完成后会被替换成_free_dbg函数,而此时我们再看看operator delete的源码

vs2013中 operator delete源码:

C++动态内存开辟_第4张图片

我们可以看代码中标黄的部分,我们就会惊奇的发现,其实C++中的opeator delete 也用的是C语言中的free函数。

new 和 delete实现原理

了解了operator new 和 operator delete 我们再来回到最开始的地方,聊聊new 和 delete 具体是怎么实现的。

  • new的原理
    1. 使用operator new 函数申请空间。
    2. 在申请上的空间上调用对应类型的构造函数。
  • delete的原理
    1. 在开辟的空间上调用对象的析构函数,完成资源清理的工作。
    2. 调用 operator delete 释放片空间
  • new[] 的实现原理
    1. 调用operator new[]函数,在operator new[]中实际调用operator new函数完成N个对象空间的申请。
    2. 在申请空间上使用N次构造函数。
  • delet[] 的实现原理
    1. 在释放的对象空间上执行N次析构函数,完成N个对象中资源的清理。
    2. 调用operator delete[]释放空间,实际在operator delete[]中调用operator delete来释放空间。

定位表达式new

定位new表达式是在已分配的原始空间中使用构造函数初始化一个对象。

使用格式:new(指针)类型

定位表达式new就像盖房子,土地已经给你准备好了,但是土地如何使用还没定,而定位表达式new就是告诉你土地如何使用的。

class Date
{
public:
	Date(int year, int month, int day) {
		_year = year;
		_month = month;
		_day = day;
	}
	void Print() {
		cout << _year << " " << _month << " " << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

int main() {
    //此时p并不是一个完整的对象,他的值为随机值
	Date* p = (Date*)malloc(sizeof(Date));
    
	//调用Date的构造函数进行初始化。
	new(p) Date(1000, 1, 1);
	return 0;
}

C和C++动态内存开辟区别

  1. malloc和free是函数,new和delete是操作符。
  2. malloc申请的空间不会初始化,new可以初始化。
  3. malloc申请空间时,需要手动计算空间大小并传递,new只需在其后跟上空间的类型即可。
  4. malloc的返回值为void*, 在使用时必须强转,new不需要,因为new后跟的是空间的类型。
  5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空,new不需要,但是new需要捕获异常。
  6. 申请自定义类型对象时,malloc/free只会开辟空间,不会调用构造函数与析构函数,而new在申请空间后会调用造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的清理。

结语

欢迎各位参考与指导!!!❤️

C++动态内存开辟_第5张图片

你可能感兴趣的:(C++学习,c++,开发语言)