C++ 引用 - 引用的特点|在优化程序上的作用

引用是C++ 的一个别名机制,所谓别名,就是同一块内存共用多个名字,每个名字都指的是这片空间,通过这些别名都能访问到同样的一块空间。

就像鲁迅和周树人是同一个人。

                                                                                                                            ——鲁迅

一、引用的基本用法

int a = 10;
int& ref = a; // ref 是 a 的引用

ref = 20; // 这也会改变 a 的值
std::cout << a; // 输出 20

需要注意的是,这里定义的引用变量ref并不会在内存上开辟新的空间,而是给a对应的那片空间取了一个新的名字,现在通过ref也能访问到那片空间了。

`&`符号我们不会陌生,在之前他的名字是取地址符,在C++中它还有新的作用:定义引用

在使用中,主要有这两个区别和联系:

   1.定义引用时:`&`在类型之后,表示该变量是引用。

int& ref = a;

  2. 获取地址时:`&`在变量前边, 表示获取该变量的地址。

int* ptr = &a;

二、引用的特点

  • 必须初始化:引用在声明时必须进行初始化。
    int& a; //错误的!!
  • 不可重新绑定:初始化后不能再指向其他变量。
    int a = 0;
    int b = 0;
    
    int& ref = a;
    int& ref = b; //错误的!!
  • 类型一致:引用的类型必须与其引用的变量类型一致。
    int a = 0;
    float& b = a; //错误的!!
  • 权限不能放大:在引用的过程中,权限可以平移,缩小,但不能放大
    const int a = 0;
    int& b = a; //权限的放大
    const int& b = a; //权限的平移
     
    int c = 0;
    const int& d = c; //权限的缩小
  • 多个别名:一个变量可以有多个引用。
    int a = 0;
    int& ref1 = a;
    int& ref2 = a;
  • 没有独立空间:在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间(在底层实现上实际是有空间的,因为引用是按照指针方式来实现的)
    int a = 0;
    int& ref = a;
  • 没有“二级引用”、没有“空引用”
    int a = 0;
    int& ref1 = NULL; //错误的!!
    int&& ref2 = a; //错误的!!

三、引用的作用

以前的交换函数我们只能通过传递参数的指针来实现,而有了引用,我们可以通过给要交换的参数取别名的方式来实现:

#include<iostream>
using namespace std;

void swap(int& a, int& b)
{
	int t = a;
	a = b;
	b = t;
}

int main()
{
	int i = 6, j = 2;
	swap(i, j);

	cout << i << endl;
	cout << j << endl;
	return 0;
}

i,j是实参,a,b是形参,且由于我们在形参类型后加了`&`,也就是说定义了a,b分别是i,j的别名,现在a,b分别代表i,j的那片空间了,所以在交换函数中我们可以通过直接交换a,b的值来交换i,j的值, 从而实现了实参传给形参,形参的改变可以改变实参的功能。

再来看一个顺序表的例子,这是没有引用前我们的写法:

struct SeqList
{
	int a[100];
	int size;
	int capacity;
};

//C实现的写法
int SLFind(struct SeqList* p, int i)
{
	// ... ...
	return p->a[i];
}

void SLModify(struct SeqList* p, int i, int x)
{
	p->a[i] = x;
}

int main()
{
	struct SeqList s;
	// ... ...
	SLFind(&s, 0);

	SLModify(&s, 0, 1);

}

要实现查找和修改这两个功能,我们分别需要`SLFind`和`SLModify` 两个函数来实现,而且需要传递顺序表结构的指针才能进行对值的修改。、

而有了引用,首先我们可以优化参数的传递:改为定义引用来接收实参,从而达到修改形参实现修改实参的功能。其次我们还可以优化程序,用一个函数就能实现修改与查找的功能:

struct SeqList
{
	int a[100];
	int size;
	int capacity;
};

//CPP实现的接口
int& SLFind(struct SeqList& p, int i)
{
	// ... ...
	return p.a[i]; // 返回引用,允许对顺序表元素进行修改
}

int main()
{
	struct SeqList s;
	// ... ...
	SLFind(s, 0) = 1;  //Modify
	cout << SLFind(s, 0) << endl;  //Find
}

在上面这段代码中,我们发现引用也可以作为返回值,但其实这一作用在某些情况下是不安全的,可以看下面这个例子:

int& add(int a, int b)
{
	int n = a + b;
	return n; //返回n的别名
}

int main()
{
	int rst = add(1, 2);
	cout << rst << endl;

	return 0;
}

这段代码的输出值是多少? 是3吗?

这段代码其实存在一个严重安全的问题:add函数返回的是局部变量 n 的引用。在 add 函数执行完毕后,局部变量 n 的生命周期结束,其内存被释放,返回的引用将指向一个已经释放的内存位置。这就像指针里我们提到的野指针。所以,具体输出的值取决于编译器,如果内存释放后编译器将这部分内存置为随机值,那么输出的值就是一个随机值。

如果改成这样呢?

int& add(int a, int b)
{
	int n = a + b;
	return n; //返回n的别名
}

int main()
{
	int& rst = add(1, 2);
	cout << rst << endl;
    cout << rst << endl;

	return 0;
}

在上一段代码是将 n 的值拷贝给 rst, 输出的 rst 取决于 存放 n 的那片内存有没有被置为随机值。

而现在变成了 rst 是 n 别名,两次打印 rst 的值可能是不同的,原因:

接下来调用 cout 函数,新建立的栈帧在原来的 add 的那片空间中

由于调用前 n 的值首先被压入栈帧,所以第一次能够成功读取到 n 的值,但第二次输出的值就是不确定的了,因为 cout 可能会覆盖到存放 n  的值的那片空间(这取决于cout所需要的栈帧空间),如果覆盖到了,那么第二次调用 cout 打印 n 的值就是随机数了。

综上所述,引用的作用有:

  1. 函数参数传递:避免拷贝,提高效率。尤其是对于传递较大的结构体时,效率的提升是显著的;
  2. 实现实参传给形参,形参的改变可以改变实参;
  3. 引用作为返回值:通过返回引用,可以在函数外部修改函数内部的变量。同时避免返回值的拷贝,从而提高性能,尤其是在返回大型对象时效果显著。

    注意,引用必须绑定有效对象:函数返回引用时,必须确保返回的引用绑定到一个有效的对象。避免返回局部变量的引用,因为局部变量在函数结束时会被销毁。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/701692.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python实现base64加密/解密

实现原理&#xff1a;导入base64库 一、加密 import base64# 加密 username "admin" base64_username base64.b64encode(username.encode(utf-8)).decode() print(base64_username) password "123" base64_password base64.b64encode(password.encod…

腾讯云大数据ES Serverless

Elasticsearch&#xff1a;日志和搜索场景首选解决方案。 技术特点&#xff1a;分布式、全文搜索和数据分析引擎&#xff0c;可以对海量数据进行准实时地存储、搜索和统计分析。 ES的技术栈一共包含四个组件&#xff1a; 其中最核心的是Elasticsearch&#xff0c;可用于数据…

halcon算子之prepare_object_model_3d详解

为某一操作准备三维对象模型。 Description 操作符prepare_object_model_3d准备3D对象模型ObjectModel3D,用于下面目的中给出的操作。它计算操作所需的值并将其存储在ObjectModel3D中,从而加快了后续操作。没有必要调用prepare_object_model_3d。但是,如果要多次使用3D对象…

低成本和颜值兼顾的 HomeLab 设备:HPE MicroServer Gen10(二)

本篇文章&#xff0c;继续分享另外一台端午假期折腾的设备&#xff0c;HP MicroServer Gen10 一代。同样分享下我的折腾思路&#xff0c;希望能够帮助到有类似需求的你。 写在前面 Gen10 “标准版”&#xff08;第一代&#xff09;和 Plus 版本设计风格一致&#xff0c;同样颜…

onlyoffice在线预览加载优化

背景&#xff1a; 使用容器部署onlyoffice到linux服务器&#xff0c;使用内网访问速度还可以接受&#xff0c;但是如果放到外网路径访问起来&#xff0c;速度就会很慢&#xff0c;甚至加载失败&#xff1b; 优化方案&#xff1a; 预览的过程排除网络因素&#xff0c;可以发现打…

(1)图像识别yolov5—安装教程

目录 1、安装YOLOv5: 2、下载预训练模型: 3、识别示例图片: 1、安装YOLOv5: 首先,你需要在你的计算机上下载 YOLOv5 的文件包,下载链接:https://github.com/ultralytics/yolov5。下载后对压缩文件进行解压。 通常使用 YOLOv5 识别物体,需要安装必要的 依赖…

海外媒体发稿渠道和方法有哪些?如何选择靠谱的国外媒体发稿服务商?

在选择海外媒体发稿服务商时&#xff0c;以下是一些关键点可以帮助您找到靠谱的服务商&#xff1a; 服务商的经验和口碑&#xff1a;查找该服务商在行业内的声誉和客户评价。拥有丰富经验和良好口碑的服务商通常更可靠。 媒体资源和覆盖范围&#xff1a;了解服务商所能提供的媒…

如何快速学会互联网运营?

答案只有一个&#xff0c;那就是选项目&#xff0c;跟团队&#xff0c;直接实操&#xff0c;比你花几千几万的学费更实在。早上就有好几位伙伴加入&#xff0c;咱们团队几乎每天都有干货分享。 作为千益畅行旅游卡源头&#xff0c;咱们没有套路&#xff0c;唯有靠谱得人心。你…

Python AI 编程助手:Fitten Code插件

一. 简介 今天为大家推荐一款适配了 Viusal Studio&#xff0c;VS Code(本文使用)&#xff0c;JetBrains 系列(本文使用)以及Vim等多种编译器环境的插件 Fitten Code&#xff0c;Fitten Code 是由非十大模型驱动的 AI 编程助手&#xff0c;它可以自动生成代码&#xff0c;提升…

肾合能量不足?揭秘手心热出汗的真相

想象一下&#xff0c;我们的身体如同一座精密的城堡&#xff0c;城堡内的每一个房间都代表着一个器官&#xff0c;而城堡的守卫——气血&#xff0c;则是维系城堡和谐稳定的重要力量。当城堡中的守卫力量不足&#xff0c;或是城堡内的环境出现紊乱时&#xff0c;城堡的某个角落…

React基础教程(07):条件渲染

1 条件渲染 使用条件渲染&#xff0c;结合TodoList案例&#xff0c;进行完善&#xff0c;实现以下功能&#xff1a; 当列表中的数据为空的时候&#xff0c;现实提示信息暂无待办事项当列表中存在数据的时候&#xff0c;提示信息消失 这里介绍三种实现方式。 注意这里的Empty是…

中霖教育怎么样?中霖教育靠谱吗?

中霖教育作为一家正经的教育机构&#xff0c;从初始到现在&#xff0c;学员的高通过率反映了我们的教学质量。 我们的目的是帮助学员通过考试&#xff0c;所以完全是根据考试来授课教学。在备考过程中掌握答题技巧&#xff0c;结合押题提分&#xff0c;只要学生严格按照老师的…

NET 使用UDP协议

1.简单的使用UDP对接示例&#xff1a; /// <summary>/// 定时器&#xff0c;每秒定时获取是否有udp数据/// </summary>public DispatcherTimer Timer1 new DispatcherTimer() { Interval new TimeSpan(0, 0, 0, 1) }; public UdpClient SocketUDP { get; set; }/…

Golang发送邮件性能如何优化?有哪些方法?

Golang发送邮件的认证流程&#xff1f;怎么设置smtp服务器发信&#xff1f; Golang作为一种高效的编程语言&#xff0c;自然也被广泛应用于发送邮件的场景。然而&#xff0c;如何优化Golang发送邮件的性能成为了一个关键问题。AokSend将探讨一些优化方法&#xff0c;以提高Gol…

高压电工作业历年试题分享(含答案)

单项选择题 1、(B)主要用于接通或断开隔离开关&#xff0c;跌落保险&#xff0c;装卸携带型接地线以及带电测量和试验等工作。A.验电器 B.绝缘杆 C.绝缘夹钳 D.绝缘手套 2、(C)的作用是用于作拉线的连接、紧固和调节。 A.支持金具 B.连接金具 C.拉线金具 D.保护金具 3、(C)是利…

python 魔术方法备忘录

python 魔术方法备忘录 网上收集了一些&#xff0c;列出了比较常用的&#xff0c;特别是第一张。 Python中的魔术方法&#xff08;Magic Methods&#xff09;&#xff0c;也被称为特殊方法&#xff08;Special Methods&#xff09;或双下划线方法&#xff08;Dunder Methods&a…

保安员精选历年试题(附答案)

一、单选题 1.保安从业人员在协助维护社会治安工作中已成为一支重要的社会(B)力量。 A:技术防范 B:安全防范 C:人力防范 D:公共防范 2.目前我国保安服务已经从单一的人力保安&#xff0c;发展为守护、(A)、押运、安全技术防范等四大主要业务。 A:巡逻 B:咨询 C:犬防 D:开锁…

Python三引号(“““)的五个神奇用法,你真的都知道吗?

大家好&#xff01;这里是快乐吗喽敲代码&#xff0c;今天我们来聊一聊 Python 中的一个神奇字符——三引号&#xff08;"""&#xff09;。三引号"""不仅仅是用来定义多行字符串的简单工具&#xff0c;它还隐藏着许多令人惊叹的用途。 什么是三引…

数据结构与算法笔记:基础篇 -递归树:如何借助树来求解递归算法的时间复杂度?

概述 我们都知道&#xff0c;递归代码的时间复杂度分析起来很麻烦。在《排序(下)》哪里讲过&#xff0c;如何用递推公式&#xff0c;求解归并排序、快速排序的时间复杂度&#xff0c;但是有些情况&#xff0c;比如快排的平均时间复杂度的分析&#xff0c;用递推公式的话&#…

软件下载网站源码附手机版和图文教程

PHP游戏应用市场APP软件下载平台网站源码手机版 可自行打包APP&#xff0c;带下载统计&#xff0c;带多套模板&#xff0c;带图文教程&#xff0c;可以做软件库&#xff0c;也可以做推广app下载等等&#xff0c;需要的朋友可以下载 源码下载 软件下载网站源码附手机版和图文…