C++从入门到放弃之:C++ 左值引用与右值引用详解

2023-11-12

C++ 引用

1. 左值引用

  • 定义
    引用即别名,某个变量的别名,对引用的操作就等同于对变量本身进行的操作,左值引用引用的对象只能是左值
  • 语法形式
    类型 & 引用名 = 变量;
int a = 100;
int &b = a;
b++;
cout<<b<<endl;//101
  • 引用使用时注意事项
  1. 引用在定义时就必须同时进行初始化,初始化以后绑定的变量不能修改
  2. 引用的类型和初始haul的变量的类型要保持一致

2. 万能引用(常引用)

  • 定义
    引用定义时加上const修饰,该引用为常引用,不能通过常引用修改绑定的目标变量的值
    const 类型& 引用名 = 变量;
    类型 const& 引用名 = 变量
int a = 100;
const int& b = a;//b就是一个常
b++;//error
a++;//101
cout <<b<<endl;//101
  • 左值和右值
    普通引用也叫左值引用,只能引用左值;而常引用也叫万能引用,即可以引用左值,也可以引用右值
  1. 左值: 可以放在赋值操作的左侧,可以被修改
  2. 右值:可以放在赋值操作的右侧,不可以被修改,(临时变量都是右值,你可以被修改)
lvalue = rvalue
  • Code

#include <iostream>
using namespace std;
int main (void){
    //int &r1 = 100;//error普通引用只能引用左值
    const int& r1 = 100;//ok
    cout << r1 << endl;//100
    int num =100;
    //首先需要将num转换成char类型,转换结果保存到系统分配的临时变量中,r2实际引用的不是num本身,而是转换后的临时变量,而临时变量是右值
    //char& r2 = num;
    const char& r2 =num;//实际引用的是临时变量(右值)
    cout << "&r2: "<<(void*)&r2<<endl;
    cout << "&num: "<<(void*)&num<<endl;
    //这时r2是临时变量的引用
    return 0;
}


$ g++ constr.cpp -o const
$ ./const
100
&r2: 0xbf9d5c1b
&num: 0xbf9d5c1c
  • 各个操作符与左值和右值的关系
/*查看各个操作符的返回值是左值还是右值*/

#include <iostream>
using namespace std;
int fun (void){
    int num = 100;
    return num ;
    //int 临时变量=num; ->将亡右值
}

int main (void){
    int a=1,b=2;
    const int c = 3;
	
	//原理:普通引用只能对应左值即左值引用
	//因此可以被int & r接收的,就可以编译通过
    //int& r = c ;//no
    //int& r = a-b;//no
    //int& r = a+b;//no
    //int& r = (b+=a);//ok
    //int& r = (a-=b);//ok
    //int& r = a++;//no
    //int& r = a--;//no
    //int& r = --a;//ok
    //int& r = ++a;//ok
    //int& r = -a;//no
    //int& r = +a;//no
    //int& r = ~a;//no
    //int& r = (fun());//no
    return 0;
}

3. 右值引用

右值引用应该是C++11引入的一个非常重要的技术,因为它是移动语义(Move semantics)与完美转发(Perfect forwarding)的基石

  • 移动语义:将内存的所有权从一个对象转移到另外一个对象,高效的移动用来替换效率低下的复制,对象的移动语义需要实现移动构造函数(move constructor)和移动赋值运算符(move assignment operator)。
  • 完美转发:定义一个函数模板,该函数模板可以接收任意类型参数,然后将参数转发给其它目标函数,且保证目标函数接受的参数其类型与传递给模板函数的类型相同。
  • 右值引用的定义
    C++11以前,右值被认为是无用的资源,所以在C++11中引入了右值引用,就是为了重用右值。定义右值引用需要使用&&:

1> 语法形式

int && rrval = 右值;
  • 右值引用一定不能被左值初始化,只能使用右值对其进行初始化
int x = 20;//左值
int && rrx1 = x;//
const int&& rrx2 = x;

2> 使用右值引用的目的
使用右值引用是为了延长用来初始化对象的声明周期,对于左值,其生命周期和其作用域有关,没有必要去延长

int  x = 20;//左值
int&& rx = x * 2;//x*2的值是一个右值,使用rx延长其声明周期,当rx被一个右值初始化以后,其就变成了一个左值
int y = rx + 2;//因此可以对其重用:42
rx = 100;	//一旦你初始化一个右值变量,该变量就程伟乐一个左值,可以被复制

当使用一个右值对象初始化一个右值引用变量以后,该右值变量就会变成左值,因此,该变量也就可以被赋值

3> 右值引用与函数参数

  • Code1
// 接收左值
void fun(int& lref)
{
    cout << "l-value reference\n";
}
// 接收右值
void fun(int&& rref)
{
    cout << "r-value reference\n";
}

int main()
{
    int x = 10;
    fun(x);   // output: l-value reference
    fun(10);  // output: r-value reference
}

通过上述代码可以看到函数重载的机制是区分左值引用与右值引用的,参数是左右引用还是右值引用是两个不同的函数重载版本


  • Code2
void fun(const int& clref)
{
    cout << "l-value const reference\n";
}

如果函数的参数为常引用,那么该函数既可以接收左值也可以接收右值(如果你没有提供右值引用的重载版本)

4. 引用型函数返回值

  • 将引用用于函数的返回类型,这时函数的返回结果就是引用的实际变量的别名,可以避免返回值所带来的内存开销,提高代码的执行效率
  • 如果函数返回类型是左值引用,那么该函数调用的表达式结果就也是一个左值,即可以对函数的表达式直接赋值
  • 注意
    可以从函数中返回成员变量,静态变量,全局变量的引用
    不可以从函数中返回局部变量的引用,因为所引用的变量的内存会在函数返回以后被释放

5. 引用和指针

  • 从C语言的角度看引用的实现,引用的本质就是指针,凡是C++中不推荐使用指针而是推荐使用引用
int i = 100;
int* const p = &i;
int& r = i;
*p <=等价=> r
  • 指针定义时可以不作初始化,指针的指向的目标可以修改(指针常量除外);
    而引用在定义时必须进行初始化,而且初始化以后,引用指向的目标不能在进行修改
  • 可以定义指针的指针(二级指针),但是不可以定义引用的指针
  • 可以定义指针的引用,但是不能定义引用的引用
  • 可以定义函数的引用(函数指针类似)即函数的别名

6. 函数传参传递指针和引用的区别

  • 指针
    指针传递参数本质上是值传递,它所传递的是一个地址值.值传递过程中,被调用函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本,值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行的,不会影响主调函数的实参变量的值(这里说的是实参指针本身的地址值不会变)
  • 引用
    引用传递的过程中,被调函数的参数形式虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址(int &a的形式).被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址,访问主调函数中的实参变量,因此,被调函数对形参做的任何操作都影响主调函数中的实参变量

总结

指针和引用的相同点和不同点:

相同点

  • 指针和引用都是地址的概念;

  • 指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。

不同点

  • 指针是一个实体,而引用仅是个别名;

  • 引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;

  • 引用没有const,指针有constconst的指针不可变;(具体指没有int& const a这种形式,而const int& a是有的, 前者指引用本身即别名不可以改变,这是当然的,所以不需要这种形式,后者指引用所指的值不可以改变)

  • 引用不能为空,指针可以为空;

  • sizeof 引用得到的是所指向的变量(对象)的大小,而sizeof 指针得到的是指针本身的大小;

  • 指针和引用的自增++运算意义不一样;

  • 引用是类型安全的,而指针不是 (引用比指针多了类型检查

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++从入门到放弃之:C++ 左值引用与右值引用详解 的相关文章

随机推荐

  • 基于正点原子STM32F103ZET6工程文件修改成C8T6工程文件

    1 打开一个正点原子的工程 点击魔术棒 2 修改芯片型号为STM32F103C8 3 修改宏定义ZET6是大容量产品用的是STM32F10X HD C8T6是中容量产品 用的是STM32F10X MD 3 更换启动文件将startup st
  • [Vue3+Element-Plus]点击列表中的图片预览时,图片被表格覆盖问题

    问题复现 源代码段
  • matlab simulink 模糊PID控制空调系统温度

    1 内容简介 略 630 可以交流 咨询 答疑 2 内容说明 随着社会不断的发展 能源问题表现的日益突出 因此 节能变得尤其重要 而现 在随着人们物质水平的提高 对中央空调系统的要求也随之提高 希望在耗能最低的情 况下 保持室内合适的温度和
  • 3-Spring笔记

    Spring容器介绍 简介 Spring是一个开源免费的框架 容器 Spring是一个针对bean的生命周期进行管理的轻量级的框架 非侵入式的 控制反转 IoC 面向切面 Aop 对事物的支持 对框架的支持 解决企业应用开发的复杂性 Spr
  • C语言实现离散傅里叶变换DFT

    离散傅里叶变换DFT的计算公式如下 关于对DFT的详细讨论 请阅读前一篇博客基于matlab的FFT分析 include
  • 蓝桥杯C/C++省赛:排它平方数

    目录 题目描述 思路分析 AC代码 题目描述 小明正看着 203879 这个数字发呆 原来 203879 203879 41566646641 这有什么神奇呢 仔细观察 203879 是个6位数 并且它的每个数上的数字都是不同的 并且它平方
  • 常见文件预览实现

    一 word文档预览 1 使用文档预览服务预览 使用微软链接 https view officeapps live com op view aspx src 文档http地址 使用XDOC链接 http view xdocin com xd
  • python/pytorch/pip安装包手动下载的网站

    https www lfd uci edu gohlke pythonlibs python安装pytorch等因为太大总是下载中断 自己手动单个下载的神器网站 conda install use local pytorch 1 3 0 p
  • 如何自己开发漏洞扫描工具

    漏洞扫描工具 核心就是扫描器 而扫描器的设计思想是 灵活 易扩展 易修改 灵活的意思就是可单独执行专项漏洞的扫描 也可以批量执行集成的所有漏洞探测模块 易扩展的意思就是 新的漏洞检测模块可清晰简单的集成进扫描器 易修改 对各个漏洞扫描模块可
  • ssh免密登录配置

    本次测试需要服务器己安装好 ssh keygen和ssh copy id 安装方式如下 安装ssh keygen root localhost yum install y ssh keygen 安装ssh copy id root loca
  • 线性代数知识点整理

    目录 前言 一 行列式 1 行列式求值 2 七大性质 3 特殊行列式的值 二 矩阵及其运算 1 行列向量 2 可逆矩阵 3 常用性质 4 伴随矩阵 三 矩阵的初等变换和线性方程组 1 初等变换 2 矩阵的秩 定义 特性 求秩 3 齐次与非齐
  • Java Swing-JScrollPane,JTable

    同事要一个和Access功能类似的软件 但是要满足她提出的各种要求 她知道我是做软件的 所以让我给写一个 想想她的提的需求很容易实现 所以就答应了 因为Access的功能她就用来管理表格 日常的很多表格很多 都需要进行电子档的登记 此软件肯
  • 【倒计时2天】CCIG文档图像智能分析与处理论坛开启直播预约,共探智能文档处理前沿技术

    文档是人们在日常生活 工作中产生的信息的重要载体 各领域从业者几乎每天都要与金融票据 商业规划 财务报表 会议记录 合同 简历 采购订单等文档 打交道 让计算机具备阅读 理解和解释这些文档图像的能力 在智能金融 智能办公 电子商务等许多领域
  • [深入研究4G/5G/6G专题-59]: 以太网交换平台软件如何升级成基站平台软件

    前言 本文从全局的视角阐述把一个通用的Linux平台软件升级成基站平台软件 一 基站的硬件 1 1 设备硬件 1 2 SOC芯片
  • 不用看网课就能学到python的文章(第三天)

    紧接着上一篇不用看网课就能学到python的文章 第二天 Why does it work的博客 CSDN博客 如果说到语句 那我们应该了解一些一些python python最具特色的就是使用缩进来表示代码块 不需要使用大括号 行与缩进 i
  • spring mvc中log4j的配置与使用

    原文地址 http rockelixir iteye com blog 1902352 如果使用spring插件创建一个spring template project 它会默认带log4j 只要改下log4j的配置就可以使用了 如果自己创建
  • ppt地图分布图一块一块的怎么做_没想到地图还能这么用,简直是PPT图表神器!...

    本期导读 如何让你的PPT看起来高大上 本文教你一个鲜为人知的视觉化技巧 利用电子地图 制作PPT图表 即便你不懂PS 不懂设计 也能轻松上手 PPT地图图表的妙用 三种PPT地图的创建方法 本文是2019年3月推送的第20篇干货 计159
  • 全国电赛K题江苏省二等奖----王澳刚

    2017年TI杯江苏省大学生电子设计大赛 题目 单相用电器分析监测装置 题目编号 K题 参赛队编号 ZJ022 参赛队学校 江苏科技大学 参赛队学生 王澳刚 雷松泽 匡正 指导老师 王宝忠 李垣江 二0一七年八月 摘 要 本系统以STM32
  • TCP:为什么是三次握手

    定义 HTTP是基于传输层的TCP协议 而TCP是一个端到端的面向连接的协议 所谓的端到端可以理解为进程到进程之间的通信 所以HTTP在开始传输之前 首先需要建立TCP连接 而TCP连接的过程需要所谓的 三次握手 在TCP三次握手之后 建立
  • C++从入门到放弃之:C++ 左值引用与右值引用详解

    C 从入门到放弃 C 引用 1 左值引用 2 万能引用 常引用 3 右值引用 4 引用型函数返回值 5 引用和指针 6 函数传参传递指针和引用的区别 总结 C 引用 1 左值引用 定义 引用即别名 某个变量的别名 对引用的操作就等同于对变量