C++基础篇——引用和指针、(const 、一级指针、引用的结合应用)、new 和 delete

本文详细介绍了C++中的引用,包括左值引用和右值引用,强调了引用的安全性和与指针的区别。接着探讨了const、一级指针与引用的结合应用,提供了转换思路。此外,文章还分析了new和delete的使用,与C语言中的malloc和free进行了对比,并列举了new的不同形式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++的引用

  • 左值引用和右值引用
  • 引用的实例

1)引用是一种更安全的指针。
2)引用只有一级引用,没有多级;指针可以有一级指针,也可以有多级指针。

int main()
{
	int a = 10;
	int *p = &a;//(指针)int *p = nullptr;编译链接没有错,但是没有输出结果
	int &b = a;//(引用)
	
	*p = 20;
	//输出结果:20 20 20 
	cout << a << " " << *p << " " << b << endl;

	b = 30;
	//输出结果:30 30 30 
	cout << a << " " << *p << " " << b << endl;

	return 0;
}

3)加断点后,转到反汇编代码,可以看出,从汇编代码的角度上里说,定义指针和定义引用说的意义是一样的,都是通过指针来实现的,都是先将a的地址放入寄存器eax,然后再将eax寄存器里面的地址放到p和b的4字节内存里;通过引用变量修改引用内存的值,和通过指针解引用修改指针指向的内存的值,其底层指令也是一模一样的。

	int *p = &a;//int *p = nullptr;编译链接没有错,但是没有输出结果
013E245F  lea         eax,[a]  
013E2462  mov         dword ptr [p],eax  
	int &b = a;
013E2465  lea         eax,[a]  
013E2468  mov         dword ptr [b],eax  

但是注意,我们在定义引用变量时,根据定义,
1、必须初始化;
2、初始化时引用变量的右值必须是一个可以取地址的值。

所以以下代码是错误的:

int &c = 20//20是一个不能取地址的值;

引用实际上相当于给数组arr起了一个别名,所以它的本质还是数组arr,如果对于使用引用不熟练,可以先定义一个指针变量,然后再将指针的取地址,换成要引用的变量,然后再用“ & ”将“ * ”
覆盖就是一个合理的引用了。

int main()
{
	int arr[5] = {};
	int *p = arr;
	//通过指针int (*q)[5] = &arr;
	//定义一个引用变量,来引用数组arr
	int (&q)[5] = arr;
	
	cout<<sizeof(arr)<<endl;
	cout<<sizeof(p)<<endl;
	cout<<sizeof(q)<<endl;

	return 0;
}

在这里插入图片描述

  • 左值引用
    左值,有内存,有名字,值可以修改,不需要生成临时变量;

  • 右值引用
    1、int &&e = 20;专门用来引用右值类型(没内存,没地址),指令上,可以自动生成临时量,然后再引用临时量,使 c = 40;
    2、右值引用变量,本身是一个左值(由内存,有地址),只能用左值引用来引用它;
    3、不能用一个右值引用变量来引用一个左值(不需要生成临时量)


int main()
{
	//左值引用
	int a = 10;
	int &b = a;

	//int &c = 20;//20是右值,没内存,没名字(错误)

	//C++11以后提供了右值引用
	int &&c = 20;
	c = 30;

	int &e = c;//一个右值引用变量,本身是一个左值(由内存,有地址)

	/*
	右值引用在汇编代码中的实际过程相当于,
	int temp = 20;//定义一个临时变量
	temp -> b //将这个临时变量赋给b
	*/
	const int &d = 20;
	//d = 30;//d 不能被修改
	system("pause");
	return 0;
}

面试题:引用和指针的区别?
答:结合上述的1) 2) 3)进行回答。

const 、一级指针、引用的结合应用

左值引用,引用地址,可以改变值,即可以理解为“变量”
右值引用,引用具体的值,没内存,没地址,即可以理解为“常量”
引用不参与类型

关于引用、指针、const ,判断代码是否正确,如果感觉对引用的理解不是那么清楚,那么可以将引用变换成指针:
1、等号右边的 取地址符‘&’移除;
2、等号左边的 引用符 ‘ & ’换成 ‘ * ’。

面试题
1、写一句代码,在内存的0x0018ff44处写一个4字节的10 ?

	int *p = 0x0018ff44;()0x0018ff44是一个整数,必须加类型强转
	int *p = (int*)0x0018ff44;//true
	int *&p = (int*)0x0018ff44;//(error)
	int * &&p = (int*)0x0018ff44;//(true)
	int * const &p = (int*)0x0018ff44;// (true)

new 和 delete

关于new 和 delete,经常和C语言中的 malloc和free联系理解,大多数时候针对以下两个问题展开,
1、new 和 malloc的区别?
2、delete 和 free的区别?

new和malloc的区别:
1)在动态开辟内存时,因为new是自己指定类型的,所以不用类型强转,而malloc则没有指定类型,所以需要类型强转;
2)new 不仅可以做内存开辟,还可以做内存的初始化操作;malloc只开辟内存,不初始化,初始化需要另写代码。

//malloc
int *p=(int*)malloc(sizeof(int);
//new
int *b = new int (40);//为b开辟空间,且初始化为40

3)malloc开辟内存失败,通过返回值和nullptr作比较;而new开辟内存失败,通过抛出bad_alloc类型的异常来判断的,对于new来说,通过malloc的异常处理方式处理异常无意义,

int main()
{
	int *p = (int*)malloc(sizeof(int));
	if (p == nullptr)
	{
		return -1;
	}
	*p = 20;
	free(p);

	int *p1 = new int(20);
	//if (p1 == nullptr)	//对于new来说,通过以下方式处理异常无意义
	//{
	//	return -1;
	//}
	
	try
	{
		int *p1 = new int(20);
	}
	catch (const bad_alloc &e)//返回异常时需要使用到特殊的头文件,这里就不讲了
	{
	}
	

	int *p1 = new int(20);
	delete p1;

	return 0}

4)malloc和free,称作C的库函数;new和delete,称作运算符的重载函数operator new / delete。

delete 和 free的区别?
1)free只能释放内存,delete先析构函数,再释放内存(free)。
2)在释放内存时,free就是一个标准的函数调用,只需要传入一个起始地址就可以了,而delete,就是加不加“[]”的问题,释放单个元素不需要,释放数组时需要加上[];

int main()
{
	//开辟数组
	int *q = (int *)malloc(sizeof(int) * 20);
	if (q == nullptr)
	{
		return -1;
	}
	free(q);
	
	int *q1 = new int[20];//没有这种初始化的方式:int *q1 = new int[20](40),每个数组的元素初始化为40
	int *q1 = new int[20]();//开辟数组后将每一个数组元素初始化为0,
							//出错时,和前面的一样,同样是返回异常
	delete[]q1;

	return 0;
}

除此之外,我们还会经常遇到一个问题,那就是,new 有多少种?根据个人了解,有以下4种,

int main()
{
	//new 有多少种?
	int *p1 = new int(20);//第一种
	
	int *p2 = new (nothrow) int;//第二种,不抛出异常版

	const int *p3 = new const int(40);//第三种,开辟了一个常量内存,所以不能直接传给int *p3,需要加上const;

	//第四种,定位new,在学习容器的空间配置器时一定会用,在堆上开辟了内存,但是具体的在哪开辟不知道。
	int data = 0;
	int *p4 = new (&data) int(50);//这个new操作把我们指定地址"&data"的内存,划分成一个整型内存块并把初值写成50 
	cout << "data: " << data << endl;
	system("pause");

	return 0;
}

第一种:内存开辟失败是通过捕获 bad_alloc异常 来判断内存开辟失败的。(抛出异常)
第二种:nothrow 不抛出异常版本的new,其返回值和nullptr判断(同malloc)(不抛出异常)
第三种:在堆上开辟了一个常量的内存,并初始化为40 。既然是常量,就只能把其地址给一个常量的指针来指向。
第四种:在容器的空间配置器上 是一定会用到的。这种new开辟内存,int* p4 = new int(50);是 在堆上开辟了一个内存,并初始化为50 。(但是这块内存在哪不清楚)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值