119-C++学习第三弹

1.解析new delete

在这里插入图片描述
new 底层调动malloc开辟object大小(自动计算)的空间 然后通过定位new调用构造函数,创建对象并初始化10,把构建好的对象的地址给op,op指向这个空间。
堆区中的这个对象是没有名字的
op->Print(); (*op).Print(); 这两种方式一样
delete op; 先调用析构函数析构对象,然后释放内存(资源)
此时是空悬指针 最好在delete op ;后加上 op=nullptr;

开辟10个对象,要调用10次构造函数,主函数结束,调用10次析构函数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

重点来了

在这里插入图片描述
系统怎么知道op是指向的是一个对象还是一组对象?
new Object[n] 开辟n个对象,系统知道连续开辟了n个对象,开辟10个Object空间,实际上new还多开辟了4个字节的空间,在上面多开辟4个空间,先记录开辟空间的个数(10记录在案),delete[]op删除的时候,它告诉其删除的是一组对象(10个),[]告诉其必须要上移4个字节来读取这里面的值(10),调用10次析构函数。
如果用delete op; 删除连续的多个空间,会导致错误。此语句只删除1个对象,而且在开辟空间的时候,有上越界标记和下越界标记,还有一个头部信息(给堆区看的),new申请空间的大小存在头部信息,创建对象个数在自己创建的空间。delete op;向上读,会产生内存读的错位,导致这里的删除让程序崩溃。
真正的op指向创建的第一个对象的地址
malloc申请空间(是用户空间)后,协议:在用户空间之上,我们给了4个字节的上越界标记,和4个字节的下越界标记,当我们访问到越界标记时,认为访问空间越界,malloc还在上面开辟28个字节,其中4个字节用于记录你申请的字节个数,free释放时可以向上读取这个值,知道当时申请的空间个数。new构建对象delete析构对象。
[]先上移4个字节来读取这里面的值(10),调用10次析构函数释放对象。然后调动free上移空间读取头部信息,知道malloc当时申请的空间,释放空间。
如果是delete op;去释放数组开辟的空间,系统认为你将释放一个对象,指向开始,读取头部信息,错了4个字节,所以读取头部信息不完整,

如果只是申请单个对象:Object *op=new Object(10);
先调用malloc申请空间(用户空间),然后有上越界标记和下越界标记,最上面是头部信息申请空间的个数。释放的时候,delete op;知道只是释放一个对象,向上读取头部信息,知道空间大小,先释放对象然后释放空间,
如果是创建一个对象,用delete[]op;,系统认为指向的这个位置点上4个字节是创建空间(对象)的个数,可是这是上越界标记,导致系统误认,导致程序崩溃,越界标记的值是FDFDFDFD(被误认为对象的个数)
在这里插入图片描述

2.引用的第二次讲解

底层 编译器编译的时候,把引用当做指针来处理
在这里插入图片描述
常引用 注意二义性
在这里插入图片描述
如果本身是变量,可以拿普通引用或者常引用
如果本身是常量,只能常引用

函数的返回类型是引用类型
在这里插入图片描述
方框是eax
引用返回的时候:本质上是地址,寄存器放的是b的地址,x=(b);把所指之物b的值给x ,这种程序实际上是错误的:当从主函数执行,调动funb,定义b,引用返回,临时空间装的是b的地址,实际上,return之后,funb的空间已经被释放了,回到主函数的时候,我们通过这个地址要抓它的值,但是这个地址的空间已经被释放了,所以我们是从失效指针抓数据了,这是不允许的,这种程序是错误的,虽然在单线程中似乎可以,但是在多线程必然有问题。局部变量生存期受到函数的影响。
注意 int &funb() return b,在系统底层看来,返回的是b的地址,int x=funb(); 系统其实是执行
(&b),把b的值10直接赋值给了x。如果是int &x=funb(); 在系统底层,&x相当于是指针x,return b;子函数相当于把b的地址给了x指针,x指针接收b的地址,而子函数执行完,子函数的空间就被释放了,如果后面还有其他函数的调用,就会打扰到这个空间,这时候输出的x的值就会是随机值或者改变的值。

右值引用
在这里插入图片描述
右值不可以取地址1.常量是右值。
int a=10; 这个10就是右值,不能取地址。系统也称重右值。
int &&c=10;右值引用,可以去引用10
int&&x=a;a不能引用,因为a是左值,不能拿右值引用
2.将亡值

左值可以取地址
在这里插入图片描述
上图这个编译不允许通过

如果再加上一个& ,编译就通过了
在这里插入图片描述
上图代码,可以把将亡值延长寿命,寿命和x等同。
右值引用将亡值
系统怎么做?
当调动主函数的时候,给主函数分配一个栈空间,当调动funa的时候,给了a=10,return的时候,产生一个副本,主函数右值引用接收,把a的副本创建到主函数的栈帧空间中,x的引用就是引用这个将亡值.将亡值和x生存期一样了。

下面这个程序对不对?
在这里插入图片描述
程序虽然运行成功,但是是错误的!!!
先看下面这个例子
在这里插入图片描述

运行后,结果是随机值!!!
在这里插入图片描述
主函数调用,给主函数分配一个栈,调用funa函数,给其分配一个栈,定义的变量为10;return以引用的形式返回a,实际上是返回a的地址,回到主函数的时候,x是引用,实际上也是一个指针,把a的地址给x,如果不调用fun,我们去打印x,funa原本在的这个空间如果不去骚扰(已经被释放),可以打印10,因为没有覆盖,如果又执行了fun,又把这个栈帧分配出来了,进行了进一步初始化,赋值,打印的要么改了要么随机值
在这里插入图片描述
引用在类中的应用
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
引用返回
此函数:可以通过它取值和赋值(对函数的返回值:当前对象的引用)

常对象不让修改值
在这里插入图片描述

因为上图这个方法是普通方法,有可能 在这个普通方法对value做手脚
看下图
在这里插入图片描述
当系统编译是,函数里面要添加Object * const this
当Object对象调用它时,把地址给this指针,对于常方法来说,它也有this指针
在这里插入图片描述
给函数加const,实际上const是修饰指针的指向不可改变。this可以指向value,但是通过this 不可以改变value的值,常引用返回。
虽然函数名相同,但是参数类型不一样,可以重载‘

拷贝构造函数

在这里插入图片描述
在这里插入图片描述

给c1分配空间,再给c2分配空间,然后调动构造函数,在c1空间,依次构建c1对象,然后到CGgood c1(c1);缺省的拷贝构造函数,把c1,c2的地址抓住,一个一个赋值进去,按位拷贝
拷贝构造函数
在这里插入图片描述
st前必须加&,否则将形成递归建立,无限循环
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
看下图这个字符串例子
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
程序运行,崩溃了!
叫做浅拷贝

在这里插入图片描述
当对象使用完,不结束,调用s2的析构函数,把指针释放了,置为空,然后调用s1的析构函数,又一次释放空间,同一个空间释放了2次

猜你喜欢

转载自blog.csdn.net/LINZEYU666/article/details/111767709