首页 > 编程语言 >深度解读C++引用

深度解读C++引用

时间:2023-04-18 19:03:41浏览次数:34  
标签:返回 变量 int C++ 解读 引用 返回值 指针

什么是引用

引用不是新定义一个变量,而是给已存在对象取了一个别名,从语言逻辑角度看,引用不占用内存空间,而与被引用的对象共用同一块内存空间。使用引用时,需要注意以下几点:

  • 引用在定义时必须初始化
  • 一个变量可以有多个引用;
  • C++中的引用一旦初始化便不能转移
  • 在语法逻辑角度,引用不占用额外的内存空间,只是某个对象的别名

深度解读C++引用_引用

引用的使用场景(意义)

做参数

输出型参数

此时形参是实参的一个别名,形参的改变会影响实参,故可以用引用做输出型参数。相比指针,引用做输出型参数显得更加明了和方便

void Swap(int& x, int& y)
{
	int tmp = x;
	x = y;
	y = tmp;
}

提高效率

传参时,使用引用可以避免参数的压栈过程,减少拷贝,以提高效率。当面对大对象和深拷贝类对象时,引用传参的效率提升非常明显。

做返回值

提高效率

由于函数栈帧会销毁,当函数返回一个值时,总是会先将返回值拷贝到一个临时变量中再返回。若返回返回值的引用,则可以避免该次拷贝而而直接返回该值以提高效率。

获取返回值

返回堆区或静态区的变量时,直接返回变量的引用不仅可以避免临时变量拷贝的开销,而且返回后可以直接对返回值进行修改,以减去一些其他冗余的操作。

struct SeqList
{
	int data[100];
	int sz;
};

int& SeqAt(SeqList& s, int pos)
{
	return s.data[pos];
}

int main()
{
	SeqList sq;
	//直接对返回值进行修改
	SeqAt(sq, 0) = 50;
	cout << sq.data[0] << endl;

	SeqAt(sq, 0) += 30;
	cout << sq.data[0] << endl;

	return 0;
}

用引用做返回值时需要注意的是,如果返回时,出了函数作用域返回对象的内存空间还未释放,则可以使用引用返回,如果内存已经释放了,则不能使用引用返回,此时返回的引用对象已被释放,内容不确定,属于非法访问

关于常引用的问题

关于常引用的问题,涉及到引用的权限问题引用的权限不能放大,只能平移或缩小,例如,不能以一个变量作为常量的引用,这是因为常量无法被修改,而变量可以被修改,也就是说权限被放大了,这是不允许的。

关于常引用还有会牵涉到其他细节:

  • 类型转换会产生一个临时变量,临时变量具有常属性,只能用常量进行引用;

深度解读C++引用_引用_02

	double d = 3.14;
	//int& i = d; // 权限放大
	const int& i = d; //权限平移
  • 上文说到,函数值返回时,会先将返回值存储到一个临时变量中,临时变量具有常属性,所以返回值只能用常量进行引用。

深度解读C++引用_类型转换_03

int Add(int x, int y)
{
	return x + y;
}

int main()
{
	//int& rret = Add(12, 10); //权限放大
	const int& rret = Add(12, 10); //权限平移
	return 0;
}

引用的底层逻辑

上文说到,引用在语法层面上不占用独立空间,与被引用对象占用同一块空间,但通过观察底层汇编代码,可以发现引用的底层实现逻辑与指针相同,也就是说,从底层汇编角度看,引用是用类似指针的方式实现的。

深度解读C++引用_类型转换_04

虽然引用的底层是指针,但是在C++中使用最多的依然是引用,这是因为相对于指针,引用往往更加明了和方便。

引用和指针的区别

  • 在语法层面上,引用不具有独立空间,与被引用对象占用同一块空间;指针存储一个对象的地址
  • 引用在定义时必须初始化;指针没有要求
  • 引用在初始化引用一个实体后就不能引用其它实体;指针可以随时改变指向而指向一个其它实体
  • 没有空引用;存在空指针
  • sizeof中的意义不同:计算引用的结果为被引用对象类型的大小;计算指针的结果始终为地址空间所占字节数(4字节或8字节)
  • 引用与常数运算,即被引用的对象进行运算;指针与常数进行运算,进行的是指针偏移(移动)
  • 有多级指针,但是没有多级引用
  • 访问实体的方式不同:指针需要显式解引用;引用编译器自行处理
  • 引用使用起来比指针更安全

标签:返回,变量,int,C++,解读,引用,返回值,指针
From: https://blog.51cto.com/158SHI/6203985

相关文章

  • 0001笔记【并行计算】CUDA在现代C++中如何运用?看这一个就够了
    目录SM(流多处理器)和板块(block)一个板块会被调度到一个SM上,直到执行结束常用函数cudaMalloc在显存上分配内存cudaMallocHost在主存上分配锁页内存cudaMemcpy在主存和显存之间拷贝数据cudaMallocManagerd统一内存优化时间依赖和空间依赖线程太多不行:防止寄存器打翻(registerspill)......
  • c++初阶入门(持续更新)
    1.命名空间目的:解决c语言的缺陷,命名冲突。#include<stdio.h>intrand=0;intmain(){printf("%d",rand);}上面这段程序是可以运行的但是!#include<stdio.h>#include<stdlib.h>intrand=0;intmain(){printf("%d",rand);}那么上面的代码就会报错。因为stdlib.h......
  • 类库项目无法引用Microsoft.AspNetCore程序集下的类库
    在类库项目中不能直接引用WebApplicationBuilder、ApplicationBuilder等类,这些类位于Microsoft.ASPNetCore程序集中,但是无法通过Nuget包引用,因为该Nuget包的版本已经不再支持,很久没有更新过了。解决方法:在项目文件csproj文件中,在ItemGroup下手动添加引用<FrameworkReferenceInc......
  • 【内附源码和文档】基于C++14异步蒙特卡洛工具函数
    Simple-Monte-Carlo-Tool-Function这是一个使用C++实现的简单的异步蒙特卡洛算法工具函数C++标准:C++14使用autores=MonteCarlo(sample_nums,check_sample_funtion,generate_sample_funtion,…args);doublep=res.get();std::cout<<p<<std::endl;sample_nums:需要生成的样......
  • C++基础1: 命名空间
    0.前言C++是在C语言基础之上的一门语言,所以学习C++的第一步是思考C++是如何优化C语言设计中的一些不足,如作用域,IO,函数,指针,宏等这些内容同时也是为之后学习C++类和对象打基础,下面说一下C++是如何优化C语言中的作用域1.命名空间在说明命名空间的概念和如何优化......
  • C++重载的奥义之运算符重载
    0、引言        重载,顾名思义从字面上理解就是重复装载,打一个不恰当的比方,你可以用一个篮子装蔬菜,也可以装水果或者其它,使用的是同一个篮子,但是可以用篮子重复装载的东西不一样。        正如在之前的文章《重载的奥义之函数重载》中介绍的类似,函数的重载是指利......
  • 初学者代码训练Day2(c/c++)
    题目接收两个双精度浮点型数据 a 和 b。输出一个浮点数表示两数相加的结果。(结果保留两位小数)要求:创建两个浮点型变量 a,b。创建两个浮点型指针变量 pa,pb 并分别将其储存的地址设为 a 的地址和 b 的地址。不要使用 a+=b 而是通过指针将变量 b 的值加到变量......
  • 4/17c++练习打卡
    #include<iostream>usingnamespacestd;classCounter{friendCounter&operator+(constCounter&a,constCounter&b);intnum;public:Counter(){num=0;}Counter(intnum_):num(num_){}//Counteroperator+......
  • 打卡 pta c++ 汽车收费
    现在要开发一个系统,管理对多种汽车的收费工作。给出下面的一个基类框架classVehicle{protected:stringNO;public:Vehicle(stringn){NO=n;}virtualintfee()=0;//计算应收费用};以Vehicle为基类,构建出Car、Truck和Bus三个类。Car的收费公式为:载客数*8+重量*2......
  • C++课本第三章课后习题 3-8
    编写函数将华氏度转化为摄氏度#include<iostream>usingnamespacestd;doublefun(doublex){return5.0*(x-32)/9;}intmain(){doublea;cin>>a;cout<<fun(a)<<endl;}编写一个函数判别一个数,是不是质数,在主程序完成输入输出。#include<iostre......