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

C++ 引用

引用可以简化原来使用指针的代码,至少看起来舒服点,不过今天发现个问题,先来看一段代码

#include <iostream>
#include <cstdlib>
#include <vector>

using namespace std;

int main() {
    vector<int> stack;
    
    stack.push_back(1);
    
    int& rx = stack[0];
    
    int vx = stack[0];

    int vy = rx;

    cout<<rx<<endl;
    
    stack.pop_back();
    
    cout<<rx<<endl;
    
    stack.push_back(2);
    
    cout<<rx<<endl;
    
    system("pause");
    return 0;
}

输出:

1
1
2

可以看到引用的值发生了变化,并且在被引用值“不存在”的情况下也返回了一个值。我们说引用的值总是存在的,因此在不会出现NULL的地方且指向不变的地方可以用引用代替指针。实际上引用是一个指针,由于引用使用的语法的规则,它必须有初值(也就是说它不会为NULL),而它的作用域(生命周期)总是等于或小于被引用的变量,而且一旦指定被引用对象后无法改变,因而使用它比直接用指针来的安全。来看一下以上部分代码在VS2012中的反汇编

    int& rx = stack[0];
00FC6495  push        0  
00FC6497  lea         ecx,[stack]  
00FC649A  call        std::vector<int,std::allocator<int> >::operator[] (0FC1276h)  
00FC649F  mov         dword ptr [rx],eax  
    
    int vx = stack[0];
00FC64A2  push        0  
00FC64A4  lea         ecx,[stack]  
00FC64A7  call        std::vector<int,std::allocator<int> >::operator[] (0FC1276h)  
00FC64AC  mov         eax,dword ptr [eax]  
00FC64AE  mov         dword ptr [vx],eax  

    int vy = rx;
00FC64B1  mov         eax,dword ptr [rx]  
00FC64B4  mov         ecx,dword ptr [eax]  
00FC64B6  mov         dword ptr [vy],ecx  

可以看到调用operator[]返回值存在eax中(函数调用约定),当初始化引用变量rx时,直接将eax给了rx,而当赋值给整型变量vx时,多了一句

013364AC  mov         eax,dword ptr [eax]

即将eax指向的内存内容重新赋值给eax,然后eax再把这个值给vx变量。从这里我们可以看出operator[]返回的eax实际上是一个指针,相应的引用rx也是一个指针,只不过在语法上做了限制,编译器做了检查和额外处理,让它用起来像一个普通值变量。比如语句

    int vy = rx;

它将一个引用赋值给一个整型变量,对应的指令序列如下

1. 首先获得指向rx引用对象的指针 (mov eax,dword ptr [rx])

2. 然后根据指针值获得被引用对象的值 (mov ecx,dword ptr [eax])

3. 最后把值赋给变量vy (mov dword ptr [vy],ecx )

再来看一个指针版本的反汇编,就会发现与引用变量相关的汇编代码几乎是一致的。

    int* p = &stack[0];
00FC64BB  lea         ecx,[stack]  
00FC64BE  call        std::vector<int,std::allocator<int> >::operator[] (0FC1276h)  
00FC64C3  mov         dword ptr [p],eax  
    int vz = *p;
00FC64C6  mov         eax,dword ptr [p]  
00FC64C9  mov         ecx,dword ptr [eax]  
00FC64CB  mov         dword ptr [vz],ecx  

这样就可以解释开始的问题了(即引用指向的值发生了改变,而且stack为empty时还能访问),因为引用实际上是一个指针,它指向stack[0]所在的内存空间,而vector会预先分配多余元素个数的空间,所以即使将vector清空了引用还是有效的(它指向的内存区没有被立即释放)。当再次push新的值放到stack[0]的位置上时,引用返回的值就是这个新的值了。

所以对于容器内元素的引用,我们应该小心使用,因为这个引用实际上只和引用初始化时被指向的容器的位置上的值相关。

转载于:https://www.cnblogs.com/lailailai/p/3616815.html

相关文章:

  • ES6 ...操作符
  • 2.Median of Two Sorted Arrays (两个排序数组的中位数)
  • 轻量级kotlin + Mvp + Rxjava + Retrofit框架
  • HDU 2722 Here We Go(relians) Again
  • yii2-queue一个好用的yii2队列操作扩展
  • ppwjs之bootstrap表格:响应式
  • [大牛翻译系列]Hadoop(22)附录D.2 复制连接框架
  • Java大小写转换
  • Transact-SQL语法速查手册
  • 开源地图数据可视化库——mapnik
  • IOS开发常用的linux命令
  • grep/字符/次数匹配/锚定符/小大括号/wc/tr/cut/sort/uniq
  • ajax跨域问题
  • 菜根谭#89
  • Kubernetes上的十大应用程序
  • angular组件开发
  • create-react-app项目添加less配置
  • javascript面向对象之创建对象
  • Mocha测试初探
  • Redis在Web项目中的应用与实践
  • Redux系列x:源码分析
  • Spark VS Hadoop:两大大数据分析系统深度解读
  • underscore源码剖析之整体架构
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 翻译--Thinking in React
  • 飞驰在Mesos的涡轮引擎上
  • 你真的知道 == 和 equals 的区别吗?
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 实现菜单下拉伸展折叠效果demo
  • 微信公众号开发小记——5.python微信红包
  • 我的业余项目总结
  • 国内唯一,阿里云入选全球区块链云服务报告,领先AWS、Google ...
  • 微龛半导体获数千万Pre-A轮融资,投资方为国中创投 ...
  • (02)Cartographer源码无死角解析-(03) 新数据运行与地图保存、加载地图启动仅定位模式
  • (附源码)ssm高校志愿者服务系统 毕业设计 011648
  • (附源码)计算机毕业设计ssm本地美食推荐平台
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (机器学习的矩阵)(向量、矩阵与多元线性回归)
  • (离散数学)逻辑连接词
  • (亲测有效)解决windows11无法使用1500000波特率的问题
  • (三维重建学习)已有位姿放入colmap和3D Gaussian Splatting训练
  • .NET Framework .NET Core与 .NET 的区别
  • .NET Micro Framework初体验
  • .NET NPOI导出Excel详解
  • .NET/C# 将一个命令行参数字符串转换为命令行参数数组 args
  • .net对接阿里云CSB服务
  • .NET是什么
  • :not(:first-child)和:not(:last-child)的用法
  • @JSONField或@JsonProperty注解使用
  • [].shift.call( arguments ) 和 [].slice.call( arguments )
  • [100天算法】-目标和(day 79)
  • [20181219]script使用小技巧.txt
  • [Assignment] C++1
  • [AX]AX2012 AIF(四):文档服务应用实例
  • [BZOJ 2142]礼物(扩展Lucas定理)