当前位置: 首页 > news >正文

C++修炼之练气期第五层——引用

目录

1.引用的概念

2.引用的性质

3.常量引用

4.使用场景

1.作参数

2.作返回值

5.传值与传引用的效率比较 

6.值和引用作为返回值的性能比较 

7.引用与指针

指针与引用的不同点


要说C语言中哪个知识点最难学难懂,大部分人可能和我一样的答案——指针。C++既然是C语言的豪华升级版肯定要优化这一问题。不过指针虽然难,但是不得不说它确实牛*呀,指针使C语言变得更加灵活更加万能,可以说指针是C/C++的精髓,因此取缔指针是万万不能的,所以C++的祖师爷引进了引用的概念。

1.引用的概念

引用给已经存在的变量取个别名;编译器不会为引用变量开辟新的内存空间,它和引用的变量共用同一块内存空间

例如:小明的小名叫作明明,不管是“明明”还是“小明”都指的是同一个人;

格式类型& 引用变量名 = 被引用的实体

//例如 ra 为 a 的引用
int a = 0;
int& ra = a;

比较一下两个变量的地址是否相同;

//比较二者的地址
cout << &a << endl;
cout << &ra << endl;

2.引用的性质

1.引用变量的类型与引用实体的类型要相同;

int a = 0;
int& ra = a;char ch = 'a';
char& rch = ch;

2.引用在定义时必须初始化;

int a = 0;
int& ra = a; 
//int& ra;    //错误的写法

3.一个变量可以有多个引用;

int a = 0;
int& b = a;
int& c = a;
//...

4.引用变量只能引用一个实体。

int a = 0;
int b = 0;int& ra = a;
ra = b;   //不能再引用其他变量
//对比指针
int* pa = &a;
pa = &b;

3.常量引用

引用常量时记得用 const 修饰,因为指针、引用在赋值或初始化时,权限可以缩小不能放大

//1.
const int a = 0;
//int& ra = a;		//编译时会报错,a为常量//权限放大
const int& ra = a;  //权限保持//int& b = 10;		//错误写法,10为常量//权限放大int c = 0;
const int& rc = c;  //权限缩小//2.
int Count()
{int a = 0;return a + 1;
}int main()
{//int& ret = Count();  //编译错误,Count 返回值为常量const int& ret = Count();return 0;
}//3.
int a = 0;
//double& b = a;    //类型错误
//double& b = (double)a;    //编译错误,类型转换时会产生临时变量
const double& b = (double)a;    //证明产生的临时变量具有常量性质

4.使用场景

目前看来,引用好像并没有什么用,接下来看一下引用经常用到的场景。

1.作参数

//形参的改变会影响实参,因为形参为实参的别名
void Swap(int& a, int& b)
{int tmp = a;a = b;b = tmp;
}//对比指针
void Swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}
//顺序表
typedef struct SeqList
{int* a;int size;int capacity;
}SL;void SLPushBack(SL* ps, int data);//C语言中void SLpushBack(SL& rs, int data);//C++中
//单链表
typedef struct Node
{int data;struct Node* next;}Node,*PNode;void SLTPushBack(Node** pphead, int data);//C语言中void SLTPushBack(Node*& phead, int data);//C++中
void SLTPushBack(PNode& phead, int data);//C++中

2.作返回值

引用作返回值时,如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

int& Count()
{static int n = 0;//出了作用域并未销毁,可用引用返回n++;return n;
}
int& Add(int a, int b)
{int c = a + b;//c出了作用域会被销毁,引用返回不可用return c;
}int main()
{int& ret = Add(1, 2);Add(3, 4);cout << "Add(1, 2) is :" << ret << endl;//看似结果为3,实则不然return 0;
}

引用作函数返回值时,调用函数时可修改返回对象

#include<assert.h>
#define N 10typedef struct Array {int a[N];int size = N;
}Array;int& Test(Array& a, int i)
{assert(i < N);return a.a[i];
}int main()
{Array a;for (int i = 0; i < N; i++){Test(a, i) = i * 10;}for (int i = 0; i < N; i++){cout << Test(a, i) << " ";}cout << endl;return 0;
}

5.传值与传引用的效率比较 

以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的一份临时的拷贝,因此用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。

//一组测试代码
#include <time.h>
struct A { int a[10000]; };
void TestFunc1(A a) {}
void TestFunc2(A& a) {}
void TestRefAndValue()
{A a;// 以值作为函数参数size_t begin1 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc1(a);size_t end1 = clock();// 以引用作为函数参数size_t begin2 = clock();for (size_t i = 0; i < 10000; ++i)TestFunc2(a);size_t end2 = clock();// 分别计算两个函数运行结束后的时间cout << "TestFunc1(A)-time:" << end1 - begin1 << endl;cout << "TestFunc2(A&)-time:" << end2 - begin2 << endl;
}int main()
{TestRefAndValue();return 0;
}

6.值和引用作为返回值的性能比较 

//一组测试代码
#include <time.h>
struct A 
{ int a[10000]; 
};A a;
// 值返回
A TestFunc1() { return a; }
// 引用返回
A& TestFunc2() { return a; }
void TestReturnByRefOrValue()
{// 以值作为函数的返回值类型size_t begin1 = clock();for (size_t i = 0; i < 100000; ++i)TestFunc1();size_t end1 = clock();// 以引用作为函数的返回值类型size_t begin2 = clock();for (size_t i = 0; i < 100000; ++i)TestFunc2();size_t end2 = clock();// 计算两个函数运算完成之后的时间cout << "TestFunc1 time:" << end1 - begin1 << endl;cout << "TestFunc2 time:" << end2 - begin2 << endl;
}
int main()
{TestReturnByRefOrValue();return 0;
}

7.引用与指针

引用与指针的用法及原理在我们使用者看来是不相同的(引用是给变量取别名,指针是指向变量的地址),但是其实引用的底层实现就是以指针的方式实现的。例如:

int main()
{int a = 10;int& ra = a;ra = 20;int* pa = &a;*pa = 20;return 0;
}

对比一下指针与引用的汇编代码,发现二者完全相同。

那么既然底层实现相同,我们是不是就不用区别引用和指针了呢?当然不是,底层实现相同可不关咱们使用者什么事,在使用时我们依旧要注意二者的区别。

指针与引用的不同点

1. 引用概念上定义一个变量的别名,指针存储一个变量地址;

2. 引用在定义时必须初始化,指针没有要求;

3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体;

4. 没有 NULL 引用,但有 NULL 指针;

5. 在 sizeof 中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节);

6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小;

7. 有多级指针,但是没有多级引用;

8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理;

9. 引用比指针使用起来相对更安全。

相关文章:

C++修炼之练气期第五层——引用

目录 1.引用的概念 2.引用的性质 3.常量引用 4.使用场景 1.作参数 2.作返回值 5.传值与传引用的效率比较 6.值和引用作为返回值的性能比较 7.引用与指针 指针与引用的不同点 要说C语言中哪个知识点最难学难懂&#xff0c;大部分人可能和我一样的答案——指针。C既然…...

从企业数字化发展的四个阶段,看数字化创新战略

《Edge: Value-Driven Digital Transformation》一书根据信息技术与企业业务发展的关系把企业的数字化分为了四个阶段&#xff1a; 技术与业务无关技术作为服务提供者开始合作科技引领差异化优势以技术为业务核心 下图展示了这四个阶段的特点&#xff1a; 通过了解和分析各个…...

vulnhub five86-1

总结:私钥登录&#xff0c;隐藏文件很多 目录 下载地址 漏洞分析 信息收集 网站渗透 爆破密码 提权 下载地址 Five86-1.zip (Size: 865 MB)Download (Mirror): https://download.vulnhub.com/five86/Five86-1.zip使用&#xff1a;下载以后打开压缩包&#xff0c;使用vm直…...

28个案例问题分析---01---redis没有及时更新问题--Redis

redis没有及时更新问题一&#xff1a;背景介绍二&#xff1a;前期准备pom依赖连接Redis工具类连接mysql工具类三&#xff1a;过程使用redis缓存&#xff0c;缓存用户年龄业务对应流程图使用redis缓存用户年龄对应代码四&#xff1a;总结一&#xff1a;背景介绍 业务中使用redis…...

[1.3_3]计算机系统概述——系统调用

文章目录第一章 计算机系统概述系统调用&#xff08;一&#xff09;什么是系统调用&#xff0c;有何作用&#xff08;二&#xff09;系统调用与库函数的区别&#xff08;三&#xff09;小例子&#xff1a;为什么系统调用是必须的&#xff08;四&#xff09;什么功能要用到系统调…...

Vue基础学习 第一个Vue程序 el挂载点 v-指令(1)

Vue简介 Vue是一个Javascript框架Vue框架可以简化Dom操作响应式数据驱动 &#xff1a; 页面是由数据生成的&#xff0c;当数据出现改动&#xff0c;页面也会即时改变 第一个Vue程序 Vue中文文档官网&#xff1a;https://v2.cn.vuejs.org/v2/guide/ 根据官方文档的说法&#…...

前端页面性能

提升页面性能的方法资源压缩合并&#xff0c;减少HTTP请求非核心代码异步加载异步加载方式&#xff1f;1)动态脚本加载、2)defer、3)async&#xff08;在加载js的时候在script标签上添加这两个属性,<script src"./test.js" charset"utf-8" defer><…...

2023-03-04 反思

摘要: 当前的时期确实比较特殊&#xff0c;不但是对于一个生命周期的最后的挣扎&#xff0c;更是在经历了各种浮浮沉沉的波澜之后还有更多的波浪。 精神分析-GRY: 非常奇怪的一个跳梁小丑, 不过我个人认为用这个标签是对跳梁小丑的侮辱和上层管理者对于这种人的纵容有很大关系…...

奇思妙想:超链接唤起本地应用

文章目录分析实现参考很多人的博客都有这样的小玩意&#xff0c;点击之后就可以直接与博主进行对话&#xff0c;而且无需添加好友。 先研究一下网页源代码&#xff1a; <a href"tencent://message/?uin88888888&Siteqq&Menuyes">联系我</a>很明…...

初识数据结构——“数据结构与算法”

各位CSDN的uu们你们好呀&#xff0c;今天小雅兰进入一个全新的内容的学习&#xff0c;就是算法和数据结构啦&#xff0c;话不多说&#xff0c;让我们进入数据结构的世界吧 什么是数据结构&#xff1f; 什么是算法&#xff1f; 数据结构和算法的重要性 如何学好数据结构和算…...

华为OD机试Golang解题 - 计算网络信号

华为Od必看系列 华为OD机试 全流程解析+经验分享,题型分享,防作弊指南)华为od机试,独家整理 已参加机试人员的实战技巧华为od 2023 | 什么是华为od,od 薪资待遇,od机试题清单华为OD机试真题大全,用 Python 解华为机试题 | 机试宝典文章目录 华为Od必看系列使用说明本期题目…...

ESP32编译及运行错误记录

1、打印格式不对 一般都是因为日志中某个参数打印格式不匹配造成。 ESP_LOGI(TAG, "[APP] Free memory: %lu bytes", esp_get_free_heap_size());//将之前的%d 改为%lu 2、配置载不对 这里选择了蓝牙模块需要引入蓝牙组件才能编译通过 idf.py menuconfig Component…...

GEE开发之降雨(CHIRPS)数据获取和分析

GEE开发之降雨CHIRPS数据获取和分析1.数据介绍2.初识CHIRPS2.1 代码一2.2 代码二3.逐日数据分析和获取4.逐月数据分析和获取4.1 代码一4.2 代码二(简洁)5.逐年数据分析和获取5.1 代码一5.2 代码二(简洁)前言&#xff1a;主要获取和分析UCSB-CHG/CHIRPS/DAILY的日数据、月数据和…...

TypeScript中面向对象

面向对象 要想面向对象&#xff0c;操作对象&#xff0c;首先便要拥有对象&#xff1b; 要创建对象&#xff0c;必须要先定义类&#xff0c;所谓的类可以理解为对象的模型&#xff1b; 程序中可以根据类创建指定类型的对象&#xff1b; 举例来说&#xff1a; 可以通过Perso…...

Transformer 模型:入门详解(1)

动动发财的小手&#xff0c;点个赞吧&#xff01; 简介 众所周知&#xff0c;transformer 架构是自然语言处理 (NLP) 领域的一项突破。它克服了 seq-to-seq 模型&#xff08;如 RNN 等&#xff09;无法捕获文本中的长期依赖性的局限性。事实证明&#xff0c;transformer 架构是…...

深入理解js中的new关键字

在js中我们经常会使用到new关键字&#xff0c;那我们在使用new关键字的时候&#xff0c;new到底做了什么呢&#xff1f;今天我们就来深入探究一下 1.初步使用 我们先来使用一下&#xff0c;这是一个正常操作 function Person() {this.name "John";}let person new…...

RT-Thread Nano(2) - 线程

参考:RT-Thread API参考手册: 线程管理 线程的分类:动态线程,静态线程 动态线程是系统自动从动态内存堆上分配栈空间的线程句柄(程序运行时再分配空间),静态线程是由用户分配栈空间与线程句柄(可以说是程序编译时已经分配好空间) 1.创建线程 创建一个动态线程 rt_thread_t …...

真香,Grafana开源Loki日志系统取代ELK?

一、Loki是什么&#xff1f; Loki是由Grafana Labs开源的一个水平可扩展、高可用性&#xff0c;多租户的日志聚合系统的日志聚合系统。它的设计初衷是为了解决在大规模分布式系统中&#xff0c;处理海量日志的问题。Loki采用了分布式的架构&#xff0c;并且与Prometheus、Graf…...

机器学习|多变量线性回归 | 吴恩达学习笔记

前文回顾&#xff1a;机器学习 | 线性回归&#xff08;单变量&#xff09; 目录 &#x1f4da;多维特征 &#x1f4da;多变量梯度下降 &#x1f4da;梯度下降法实践 &#x1f407;特征缩放 &#x1f407;学习率 &#x1f4da;特征和多项式回归 &#x1f4da;正规方程 &…...

高并发内存池

按照threadcache&#xff0c;centralcache&#xff0c;pagecache顺序所列 这里还需要一定的前期准备工作 首先是可以设计一个定长内存池 ObjectPool.h #pragma once #include<iostream> #include"Common.h" using std::cout; using std::endl; using std::…...

Docker 离线安装指南

参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性&#xff0c;不同版本的Docker对内核版本有不同要求。例如&#xff0c;Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本&#xff0c;Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...

工业安全零事故的智能守护者:一体化AI智能安防平台

前言&#xff1a; 通过AI视觉技术&#xff0c;为船厂提供全面的安全监控解决方案&#xff0c;涵盖交通违规检测、起重机轨道安全、非法入侵检测、盗窃防范、安全规范执行监控等多个方面&#xff0c;能够实现对应负责人反馈机制&#xff0c;并最终实现数据的统计报表。提升船厂…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

linux 下常用变更-8

1、删除普通用户 查询用户初始UID和GIDls -l /home/ ###家目录中查看UID cat /etc/group ###此文件查看GID删除用户1.编辑文件 /etc/passwd 找到对应的行&#xff0c;YW343:x:0:0::/home/YW343:/bin/bash 2.将标红的位置修改为用户对应初始UID和GID&#xff1a; YW3…...

Module Federation 和 Native Federation 的比较

前言 Module Federation 是 Webpack 5 引入的微前端架构方案&#xff0c;允许不同独立构建的应用在运行时动态共享模块。 Native Federation 是 Angular 官方基于 Module Federation 理念实现的专为 Angular 优化的微前端方案。 概念解析 Module Federation (模块联邦) Modul…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

docker 部署发现spring.profiles.active 问题

报错&#xff1a; org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

Android第十三次面试总结(四大 组件基础)

Activity生命周期和四大启动模式详解 一、Activity 生命周期 Activity 的生命周期由一系列回调方法组成&#xff0c;用于管理其创建、可见性、焦点和销毁过程。以下是核心方法及其调用时机&#xff1a; ​onCreate()​​ ​调用时机​&#xff1a;Activity 首次创建时调用。​…...