C++引用深度详解
C++引用深度详解
- 前言
- 1. 引用的本质与核心特性
- 1.1 引用概念
- 1.2 核心特性
- 2. 常引用与权限控制
- 2.1 权限传递规则
- 2.2 常量引用
- 2.3 临时变量保护
- 1. 样例
- 2. 样例
- 3. 测试
- 三、引用使用场景分析
- 3.1 函数参数传递
- 输出型参数
- 避免多级指针
- 高效传参
- 3.2 做函数返回值
- 正确使用
- 危险案例
- 4. 性能对比实验
- 4.1 参数传递效率
- 4.2 返回效率对比
- 5. 引用与指针的终极对比
- 5.1 底层实现
- 5.2 特性对比表
- 6. 高级应用技巧
- 6.1 链式操作
- 7. 总结引用要点
- 8. 最佳实践指南
前言
本文深度探索引用的各种用法和特性。介绍引用的语法,核心特性,引用的权限控制,常引用以及引用的各种使用场景。
1. 引用的本质与核心特性
1.1 引用概念
引用(Reference)是C++引入的重要特性,是 C++ 中的一种数据类型。
从语法层面讲,引用是变量的别名。与指针不同,引用在语法层面不开辟新空间,而是与原变量共享内存地址。
引用不会创建新的对象,只是创建另一个访问现有对象的方式,引用类型变量是已有变量的别名。
引用在语法上与指针类似,但其语义和使用方式不同。
我们创建一个变量,其实就是对一块内存空间
取名字
而创建引用类型对象,就是对已有的一块空间取第二个名字。
两个名字代表的是同一块空间。
int main() {int a = 10;int& ra = a; // ra是a的别名ra = 20; // 修改ra等同于修改acout << a; // 输出20
}

可以看到:
- 对ra进行操作,也就是对a进行操作。
- 变量
ra和ra具有相同的地址。
1.2 核心特性
| 特性 | 说明 | 示例验证 |
|---|---|---|
| 必须初始化 | 定义时必须绑定实体 | int& r; 编译错误 |
| 不可重绑定 | 绑定后不能指向其他变量 | int b=20; ra=b; 实为赋值 |
| 类型严格匹配 | 必须与实体类型一致 | double d=1.1; int& rd=d; 错误 |
| 多级别名支持 | 可对引用再次引用 | int& rra=ra; 合法 |
int main() {int a = 666;int num = 100;int& b = a;int& c = b; //可对引用再次引用int& d = c; //可对引用再次引用//int& e; //引用必须初始化,该语句编译会报错。cout << d << endl;d = num; //引用一旦指定,不可修改 所以这里是 赋值, 是把num的值 100 赋值给 d cout << &a << endl; //输出的地址相同cout << &b << endl;cout << &c << endl;cout << &d << endl;cout << a << endl; //输出的值相同cout << b << endl;cout << c << endl;cout << d << endl;
}

- 引用必须初始化
- 引用一旦指定,不可重绑定
- 引用的类型严格匹配
- 一个变量可以有多个引用(多个别名),引用变量也可以有引用(引用的别名)。
- 在语法层面上, 我们认为 引用没有开辟新空间, 只是对同一片内存空间取了多个名字
2. 常引用与权限控制
2.1 权限传递规则
| 操作 | 合法性 | 说明 |
|---|---|---|
| 变量 → 常引用 | ✔️ | 权限缩小 |
| 常量 → 非 常引用 | ❌ | 权限放大 |
| 常引用 → 常引用 | ✔️ | 权限不变 |
注意事项:
- 权限可以平移。
- 权限可以缩小。
- 权限不能放大。
看如下,此处有报错,为什么?

1. 首先声明,每个变量名都有其相应的权限。
2. 也就是说,每块内存,都有相应的权限。
3. 引用,就是对一块内存起了别名
int x = 0, 创建变量xint& y = x, y是x的引用。此处, y是int型的引用,发生了权限的平移。const int& z = x, 此处发生了权限的缩小。该内存块在使用名字z时,权限为const,不能修改。- 名字x和y权限相同,即, 该内存块在使用名字
x和y时,可以修改 - 因此
++x正确,++z会报错。
2.2 常量引用
int main() {const int a = 10;//int& ra = a; //编译出错,因为 a为常量const int& ra = a; //正确写法//int& b = 10; //编译出错,因为 10 为常量, 该语句产生了权限的放大const int& b = 10; //正确写法return 0;
}
- 对
const int a = 10;, 有int& ra = a, 编译出错,因为 a为常量, 该语句发生了权限的放大
2.3 临时变量保护
1. 样例
声明1:在C/C++中,只要发生类型转换,就会产生临时变量。
声明2:临时变量具有常性(不能修改)。
类型转换时会产生具有常性的临时变量,看以下例子:
double d = 12.34;//int& rd = d; //编译出错,因为 类型不同const int& rd = d; // 合法,等价于:// int temp = d; // d为3.14, 常量// const int& rd = temp;
以上过程如下:

- 引用时发生类型转换,实质上是对临时变量的引用。
- 临时变量具有常性。
double d = 12.34,//int& rd = d; //编译出错。临时变量具有常性,实质上可以理解为:int& rd = const temp发生了权限的放大,因此报错。 - 临时变量具有常性。
const int& rd = d, 实质上可以理解为:const int& rd = const d, 是权限的转移。因此正确。
2. 样例
声明3:函数在进行值返回时,返回的同样是临时变量。该临时变量是原函数的拷贝。

实际上返回的是具有常性的临时变量。
清楚了这一点后,以下例子的原理同上。
//例子
int func1() { //返回x的拷贝,会产生临时变量static int x = 10;return x;
}int& func2() { //返回x的别名, 不会产生临时变量static int x = 10;return x;
}
int main() {//int& x = func1(); //权限放大,错误。int x1 = func1(); // 仅拷贝const int& y = func1(); //权限平移,可以进行int& ret2 = func2(); //可以,权限的平移 const int& ret2_ = func2(); //可以,权限的缩小//总结,func返回的是一个变量的别名, return 0;
}
3. 测试
//测试类型转换时会产生临时变量
int main() {int i = 10;double j = 10.11;//过程:double temp = i; double j = temp//该过程会发生类型提升//一般是小的往大的进行类型提升,提升的时候不能改变原变量。//因此只能产生原变量的副本,即临时变量if (j > i) //此处是 double j 和 double i的比较cout << "xxxxxxxxxxxxx" << endl;return 0;
}
运行结果如下:

三、引用使用场景分析
3.1 函数参数传递
输出型参数
//利用引用,可以避免指针和多级指针
void Swap(int& a, int& b) { //交换值 形参是实参的别名int temp = a;a = b;b = temp;
}
避免多级指针
void Swap(int*& a, int*& b) { //交换指针 如果不用引用,交换指针变量需要用二级指针int* temp = a;a = b;b = temp;
}
高效传参
struct BigData { int arr[10000]; };// 值传递:拷贝4w字节
void ProcessData(BigData data); // 引用传递:仅传地址(4 或 8字节)
void ProcessDataOpt(const BigData& data);
3.2 做函数返回值
正确使用
int& GetStatic() {static int count = 0;return count; // 静态变量, 生命周期足够
}
危险案例
int& DangerousRet() {int local = 10;return local; // 返回局部变量引用!
}
- 如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回。
- 如果已经还给系统了,则必须使用传值返回。
不能返回局部对象(变量)的引用。
4. 性能对比实验
4.1 参数传递效率
struct HugeStruct { int data[10000]; };void ValueFunc(HugeStruct hs) {} // 值传递
void RefFunc(const HugeStruct& hs) {} // 引用传递// 测试结果(10000次调用):
// 值传递耗时:1587ms
// 引用传递耗时:2ms
4.2 返回效率对比
HugeStruct g_data;HugeStruct ReturnByValue() { return g_data; }
HugeStruct& ReturnByRef() { return g_data; }// 测试结果(100000次调用):
// 值返回耗时:3521ms
// 引用返回耗时:1ms
5. 引用与指针的终极对比
5.1 底层实现
; 引用实现
mov dword ptr [a], 0Ah
lea eax, [a] ; 取地址
mov dword ptr [ra], eax ; 指针实现
mov dword ptr [a], 0Ah
lea eax, [a]
mov dword ptr [pa], eax
关键区别
- 引用:在 C++ 中引用通常会被优化为指针,底层是通过地址访问,但语法上没有指针的显式解引用和取地址操作。
- 指针:指针显式地存储内存地址,允许进行指针算术操作,指针本身也可以为空(
nullptr)。
从底层来看,引用和指针的实现非常相似,都是通过存储地址来实现对变量的间接访问。区别在于语法和语义上,引用在 C++ 中看起来更像是变量的别名,而指针则显式地表示地址。
5.2 特性对比表
| 特性 | 引用 | 指针 |
|---|---|---|
初始化要求 | 必须 | 可选 |
空值 | 无NULL引用 | 支持NULL |
重定向 | 不可 | 可以 |
访问方式 | 直接访问 | 需解引用(*或->) |
类型安全 | 更高 | 较低 |
多级间接 | 单级 | 支持多级 |
sizeof | 返回原类型大小 | 返回地址大小(4或8字节) |
6. 高级应用技巧
6.1 链式操作
struct Matrix {Matrix& Transpose() { /*...*/ return *this; }Matrix& Rotate(double angle) { /*...*/ return *this; }
};Matrix mat;
mat.Transpose().Rotate(45); // 链式调用
7. 总结引用要点
- 引用概念上定义一个变量的别名,指针存储一个变量地址。
- 引用在定义时必须初始化,指针没有要求
- 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
- 没有NULL引用,但有NULL指针
- 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
- 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
- 有多级指针,但是没有多级引用
- 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
- 引用比指针使用起来相对更安全
8. 最佳实践指南
- 优先const引用:函数参数尽量使用
const T&形式 - 警惕返回引用:确保返回对象生命周期足够
- 替代输出参数:用引用替代指针作为输出参数
- 类型转换注意:隐式转换产生临时变量需用const引用
- 与智能指针配合:
std::shared_ptr<T>&管理资源(后续讲解)
以上就是关于引用的所有内容了,码字整理不易,欢迎各位大佬在评论区交流
相关文章:
C++引用深度详解
C引用深度详解 前言1. 引用的本质与核心特性1.1 引用概念1.2 核心特性 2. 常引用与权限控制2.1 权限传递规则2.2 常量引用2.3 临时变量保护1. 样例2. 样例3. 测试 三、引用使用场景分析3.1 函数参数传递输出型参数避免多级指针高效传参 3.2 做函数返回值正确使用危险案例 4. 性…...
SpringCloud - Gateway 网关
前言 该博客为Sentinel学习笔记,主要目的是为了帮助后期快速复习使用 学习视频:7小快速通关SpringCloud 辅助文档:SpringCloud快速通关 源码地址:cloud-demo 一、简介 官网:https://spring.io/projects/spring-clou…...
【JVM详解五】JVM性能调优
示例: 配置JVM参数运行 #前台运行 java -XX:MetaspaceSize-128m -XX:MaxMetaspaceSize-128m -Xms1024m -Xmx1024m -Xmn256m -Xss256k -XX:SurvivorRatio8 - XX:UseConcMarkSweepGC -jar /jar包路径 #后台运行 nohup java -XX:MetaspaceSize-128m -XX:MaxMetaspaceS…...
基于 STM32 平台的音频特征提取与歌曲风格智能识别系统
标题:基于 STM32 平台的音频特征提取与歌曲风格智能识别系统 内容:1.摘要 摘要:本文介绍了一种基于 STM32 平台的音频特征提取与歌曲风格智能识别系统。该系统通过对音频信号进行特征提取和分析,实现了对歌曲风格的自动识别。在特征提取方面,…...
DeepSeek:搅动人工智能产业风云的鲶鱼效应深度解读
我的个人主页 我的专栏:人工智能领域,希望能帮助到大家!!!点赞❤ 收藏❤ 引言 在当今科技飞速发展的时代,人工智能(AI)无疑是最为耀眼的领域之一。众多技术与平台如繁星般涌现&a…...
一觉醒来全球编码能力下降100000倍,新手小白的我决定科普C语言——三子棋游戏实现
硬控我一上午,小编还是太菜了,大家可以自行升级电脑难度,也可以升级游戏到五子棋 1.game.h #pragma once #include<stdio.h> #include<stdlib.h> #include<time.h> #define ROW 3 #define COL 3//初始化棋盘 void InitBoa…...
学习 URL 传参中哪些字符是支持的,哪些是不支持的
URL 的结构 URL 由多个部分组成,包括协议、域名、路径、查询参数和片段标识符,其中,查询参数部分就是问号后面的内容,这部分使用键值对,中间用 & 分隔。比如,http://example.com/path?key1value1&…...
bingAI生成的易语言编程基础
易语言编程基础 易语言(EPL)是一种基于中文的编程语言,旨在简化编程学习过程,特别适合初学者和有一定编程基础的开发者。它通过中文关键词和语法,降低了编程的门槛,使得代码更加直观易懂。 示例ÿ…...
HTML应用指南:利用POST请求获取接入比亚迪业态的充电桩位置信息
在新能源汽车快速发展的今天,充电桩的分布和可用性成为了影响用户体验的关键因素之一。比亚迪作为全球领先的新能源汽车制造商,不仅在车辆制造方面取得了卓越成就,也在充电基础设施建设上投入了大量资源。为了帮助用户更方便地找到比亚迪充电桩的位置,本篇文章,我们将探究…...
高斯消元法及其C++实现
深入浅出高斯消元法及其C实现 本文章代码由博主编写但是文章由ChatGPT-o1-mini生成 博客食用更佳 在计算机算法竞赛中,线性方程组的求解是一个常见且基础的问题。高斯消元法作为一种经典的算法,因其高效和直观的特性,广泛应用于各种编程竞赛和…...
DeepSeek AI R1推理大模型API集成文档
DeepSeek AI R1推理大模型API集成文档 引言 随着自然语言处理技术的飞速发展,大语言模型在各行各业的应用日益广泛。DeepSeek R1作为一款高性能、开源的大语言模型,凭借其强大的文本生成能力、高效的推理性能和灵活的接口设计,吸引了大量开发…...
【算法-动态规划】、魔法卷轴: 两次清零机会整个数组最大累加和
【算法-动态规划】、魔法卷轴: 两次清零机会整个数组最大累加和 文章目录 一、dp1.1 题意理解1.2 整体思路1.3 具体思路1.4 代码 二、多语言解法 一、dp 1.1 题意理解 nums 数组, 有正负0, 使用最多两次魔法卷轴, 希望使数组整体的累加和尽可能大. 求尽可能大的累加和 其实就…...
【R】Dijkstra算法求最短路径
使用R语言实现Dijkstra算法求最短路径 求点2、3、4、5、6、7到点1的最短距离和路径 1.设置data,存放有向图信息 data中每个点所在的行序号为起始点序号,列为终点序号。 比如:值4的坐标为(1,2)即点1到点2距离为4;值8的坐标为(6,7)…...
深入浅出:探索 DeepSeek 的强大功能与应用
深入浅出:探索 DeepSeek 的强大功能与应用 在人工智能技术飞速发展的今天,自然语言处理(NLP)作为其重要分支,正逐渐渗透到我们生活的方方面面。DeepSeek 作为一款功能强大的 NLP 工具,凭借其易用性和高效性…...
西门子S7-200 PLC串口PPI转以太网通讯的模块链接方式
项目背景 某汽车零部件生产车间有30台自动化生产设备,控制系统采用西门子S7-200系列的CPU226。此前,设备的一个通讯端口用于和变频器进行自由口通讯,另一个通讯端口连接着一台昆仑通态触摸屏作为人机界面。车间计划进行智能化升级ÿ…...
win10向windows server服务器传输文件
win10向windows server服务器传输文件 遇到无法直接拖动文件进行传输时 解决方案: 1.点击显示选项 2.点击本地资源-详细信息 3.在窗口中选择你需要共享的磁盘 4.然后远程连接到Windows server服务器 5.登录Windows server服务器后,在此电脑下就能看…...
git服务器搭建,gitea服务搭建,使用systemclt管理服务
文章目录 页面展示使用二进制文件安装git服务下载选择架构使用wget下载安装 验证 GPG 签名服务器设置准备环境创建systemctl文件 备份与恢复备份命令 (dump)恢复命令 (restore) 页面展示 使用二进制文件安装git服务 所有打包的二进制程序均包含 SQLite,MySQL 和 Po…...
Mybatis快速入门与核心知识总结
Mybatis 1. 实体类(Entity Class)1.1 实体类的定义1.2 简化编写1.2.1 Data1.2.2 AllArgsConstructor1.2.3 NoArgsConstructor 2. 创建 Mapper 接口2.1 Param2.2 #{} 占位符2.3 SQL 预编译 3. 配置 MyBatis XML 映射文件(可选)3.1 …...
用docker在本地用open-webui部署网页版deepseek
前置条件 用Ollama在本地CMD窗口运行deepseek大模型-CSDN博客文章浏览阅读109次,点赞5次,收藏2次。首次运行需要下载deepseek的大模型包(大约5GB,根据本地网速的不同在半个小时到几个小时之间下载完成) ,并…...
2025.2.8——一、[护网杯 2018]easy_tornado tornado模板注入
题目来源:BUUCTF [护网杯 2018]easy_tornado 目录 一、打开靶机,整理信息 二、解题思路 step 1:分析已知信息 step 2:目标——找到cookie_secret step 3:构造payload 三、小结 一、打开靶机,整理信…...
前端实现在PDF上添加标注(1)
前段时间接到一个需求,用户希望网页上预览PDF,同时能在PDF上添加文字,划线,箭头和用矩形框选的标注,另外还需要对已有的标注进行修改,删除。 期初在互联网上一通搜索,对这个需求来讲发现了两个问…...
【CXX-Qt】1.1 Rust中的QObjects
本文涉及到了使用CXX-Qt将Rust、C和QML集成到Qt应用程序中的各个方面。下面,我将提供一个简单的示例,演示如何使用CXX-Qt来创建一个Rust结构体并将其作为QObject子类暴露给C和QML。 一、设置CXX-Qt环境 首先,确保您已经安装了Rust、CXX和CX…...
操作系统中的任务调度算法
一、引言 在操作系统中,任务调度算法是核心组件之一,它负责合理分配有限的 CPU 资源,以确保系统的高效运行和良好的用户体验。任务调度的目标是实现公平性、最小化等待时间、提高系统吞吐量,并最大化 CPU 的利用率。不同的任务调…...
GitCode 助力 Easy-Es,革新 Elasticsearch 开发体验
项目仓库(点击阅读原文链接可直达) https://gitcode.com/dromara/easy-es 项目背景:填补 Elasticsearch ORM 框架空白 在 Java 开发领域,Excel 和 Elasticsearch 的代码编写难度一直名列前茅,尤其是 Elasticsearch&a…...
线程同步(互斥锁与条件变量)
文章目录 1、为什么要用互斥锁2、互斥锁怎么用3、为什么要用条件变量4、互斥锁和条件变量如何配合使用5、互斥锁和条件变量的常见用法 参考资料:https://blog.csdn.net/m0_53539646/article/details/115509348 1、为什么要用互斥锁 为了使各线程能够有序地访问公共…...
EF Core中实现值对象
目录 值对象优点 值对象的需求 值类型的实现 值类型GEO的实现 值类型MultilingualString的实现 案例:构建表达式树,简化值对象的比较 值对象优点 把有紧密关系的属性打包为一个类型把领域知识放到类的定义中 class shangjia {long id;string nam…...
《从入门到精通:蓝桥杯编程大赛知识点全攻略》(十一)-回文日期、移动距离、日期问题
前言 在这篇博客中,我们将通过模拟的方法来解决三道经典的算法题:回文日期、移动距离和日期问题。这些题目不仅考察了我们的基础编程能力,还挑战了我们对日期处理和数学推理的理解。通过模拟算法,我们能够深入探索每个问题的核心…...
Kubernetes 最佳实践:Top 10 常见 DevOps/SRE 面试问题及答案
1. 如何在 Kubernetes 中设置资源请求和限制? 资源请求确保容器有最小资源量(CPU/内存),而限制则强制容器消耗的最大资源量。这有助于高效资源分配并防止资源争用。 示例: resources:requests:memory: "256Mi&…...
Docker Compose介绍及安装使用MongoDB数据库详解
在现代容器化应用部署中,Docker Compose是一种非常实用的工具,它允许我们通过一个docker-compose.yml文件来定义和运行多容器应用程序。然而,除了Docker之外,Podman也提供了类似的工具——Podman Compose,它允许我们在…...
科普:数据仓库中的“指标”和“维度”
在数据仓库中,指标和维度是两个核心概念,它们对于数据分析和业务决策至关重要。以下是对这两个概念的分析及举例说明: 一、指标 定义: 指标是用于衡量业务绩效的关键数据点,通常用于监控、分析和优化企业的运营状况。…...
