C++【new & delete】【operator new & operator delete】

目录

数据段存储位置的小复习

new 和 delete

operator new 和 operator delete

new和delete调用operator new和operator delete

new [ ] 和 delete [ ]的原理


数据段存储位置的小复习

全局变量和静态变量都在静态区,也称数据段

全局变量int x = 0 和 全局静态变量static int c = 0 的区别

int x = 0 可以在所有文件可以用,而static int c = 0 只能在当前文件可用

char num[] ="abcde";

这行代码中的 *num在计算机里的什么地方

因为在赋值的时候,常量”abcde" 会拷贝一份给num,此时*num就是拷贝常量区的字符串内容

所以*num在栈上面


new 和 delete

动态申请一个int空间
int* p1 = new int

动态申请一个int空间,并初始化为10
int* p2 = new int(10);

动态申请十个int空间
int* p3 = new int[10];

多个数据初始化,例如
int* p4 = new int[3]{1,2,3};

 如果不初始化的话,系统不会帮你初始化,因为它只是帮我们开空间

如果没有初始化完全,就好比我开了10个空间,但我值初始化了3个,其它的便会默认初始化0

删除的话,有方括号要带方括号,没方括号的可不带

delete p1;
delete p2;
delete[] p3;
delete[] p4;

引用new和delete的原因是:

malloc不方便解决动态申请的自定义类型的对象的初始化问题

eg:我们有一个A类

只是malloc的话:

A* p = (A*)malloc(sizeof(A));

我们怎么对它初始化,初始化不了啊,它甚至都没有构造函数的概念,怎么调用啊

new的作用:

  1. 开空间;
  2. 调用默认构造函数; 
  3. 可以显示调用

现在来展示一下3

A* a = new A(1);

 还可以同时开辟多个对象

A aa1(1);
A aa2(1);
A aa3(1);

A* p1 = new A[3]{aa1,aa2,aa3};
A* p2 = new A[3]{A(2),A(2),A(2)};
A* p3 = new A[3]{3,3,3};

 所以,new的本质就是开空间和调用构造函数初始化

delete的本质就是调用析构和释放空间

class Stack {
private:
	int* _a;
	int _top;
	int _capacity;
public:
	Stack(int capacity=4)
	{
		cout << "我调用了构造函数" << endl;
		_a = new int[capacity];
		_top = 0;
		_capacity = capacity;
	}

	~Stack() {
		cout << "析构!启动!" << endl;
		delete[] _a;
		_a = nullptr;
		_top = 0;
		_capacity = 0;
	}
};
	Stack* p = new Stack;
	delete p;

我们都知道,new的主要功能是开空间+调用构造函数,

但是在Stack*  p  = new Stack;这条语句中,它不是已经先new了一下吗,那么构造函数里又new的是什么,delete又该咋办

 构造的时候第一次new的是类的空间,第二次new的_a指向的空间

调用构造,构造的有_a指向的空间

释放的时候第一次delete的是_a指向的空间,第二次是p指向的空间

析构的有_a指向的空间


operator new 和 operator delete

new和delete是用户进行动态内存申请和释放的操作符,operator new和operator delete是系统提供的全局函数。

new是底层调用operator new全局函数来申请空间,delete在底层通过operator delete全局函数来释放空间

operator new和operator delete不是对new和delete的重载,它们就只是全局函数

可以认为封装了malloc和free,也就是说,operator new和operator delete的功能是跟malloc和free的功能一样的,只不过给它加了一个抛异常的功能

 

operator new和operator delete只负责开空间,并不负责调用构造函数和析构函数

  那既然malloc和operator那么相似,为什么不直接用malloc呢

那是因为malloc如果失败了,返回的是0,在C++中,即面向对象编程的过程中,出现了错误不能只返回0,而是要抛异常,malloc抛不了一场,但operator new能抛异常,所以选择operator new


new和delete调用operator new和operator delete

所以,在Stack* p = new Stack这串代码中,可以很清楚的看到

new先调用了operator new这个函数,然后再去调用Stack()这个构造函数

此种行为就是new的功能:开空间+构造函数 

同理

delete也是先调用了~stack(),然后再调用operator delete()函数

此种行为就是delete功能:释放类内开辟的空间,再释放类

一开始,我们会找不到operator delete函数调用,别急,我们进去(07FF7F2331532h)这个地址里面看看

再进去框框里面的地址,进到析构内部 

我们平常不会用operator new和operator delete,只是会间接调用


new [ ] 和 delete [ ]的原理

new Stack[10] 中,new只调用了一次operator new[ ] ,operator new [ ]是封装了operator new的函数,里面创建了有10个Stack类大小的空间

但是,调用构造函数调用了10次

delete[ ]  原理类似

为何是16,为何不是12,,我们知道*p3相当于p3[0],但是一个Stack,最多才12字节,为什么会多出4字节呢?

原因是:我们进入内存来去查看

自定义类型的时候,new的时候会多开四个字节,为了给delete[ ]准备,因为delete不知道

告诉它之后,就告诉delete [ ] 先调用10个析构函数,再去调用operator delete [ ]

operator delete [ ] 再去调用operator delete ,operator delete 再去调用free( )

free需要想办法,将开始的地址往后减到标记数量的那块地址上,再开始free( )

因为多了四字节的原因,因此在使用delete 和 delete[ ]  的时候,需要严格按照与new和 new[ ] 配对来完成释放空间的工作

比如,如果,我在开空间的时候用的是new [ ] ,而在释放空间的时候用的是 delete ,结果就会崩溃

原因是,delete识别不到多的四字节,导致在释放位置的时候到不了标注开了多少块空间的那个地址位置,所以漏了4字节空间没释放,最后导致崩溃。

析构函数可以显示调用,构造函数一般不能被显示构造

但可以通过定位new (placement-new)来显示调用构造函数,这个涉及到内存池

以上便是本次博文的学习内容,如有错误,还望各位大佬指点出来,谢谢阅读

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值