由底层和逻辑说开去--c++之引用的深入剖析
在学c++的时候 我遇到的第一个问题就是这个引用,引用是什么东西,我的c++启蒙教科书是c++ primer plus,这本书上说的是:引用是已定义变量的别名,可以使用这个引用来表示这个变量;每当看到这句话的时候 我就有一种淡淡的的忧伤感,其实还是不懂, 这句话说的意思是说引用是个名字吗,那么引用占多大内存呢,我把这章从头看到尾 可惜对此只字不提, 由此可见写书者的诚意(至少我看不到), 本文就准备解析一下这个引用到底是个什么东东。
先说一下本文的结构,本文主要由三个问题1,引用占内存吗,多大 2.引用跟指针啥关系 3.为什么要发明引用呢?针对这三个问题本文希望从c逻辑和汇编底层层面进行剖析,如有疏漏,还请大家批评指教。
首先第一个问题是引用占内存吗:为了回答这个问题,我们可以用假设验证法;假设1,引用是个名字而已,不占内存,这个我觉得是有些书和老师要传达给我的想法(起码让我这样想了),2.引用占内存,内存大小和它所引用的变量的大小,一样大(这个听起来貌似也有点道理);假设3,引用跟指针一样大,在x86架构上是32位的,就像指针一样(这个是根据引用的作用跟指针相似推出的); 那么我们就写个程序来测一测哪个对喽:
#include <iostream>
using namespace std;
class Data
{
public:
char a;
char & b;
Data():b(a)
{} };
int main()
{
Data d;
cout<<sizeof (d)<<endl;
return 0;
}
看上面的代码,这个对象呢,包含两种类型的变量,一个是char 型的变量另一个是它的引用,那就蛋疼了,这个对象到底是多大的呢;
如果假设1,成立那应该是1,如果假设2成立,那应该是2,如果假设三成立,应该是大于4的倍数也就是8(这里其实是内存对齐机制大家可以测试一个char 和一个int 组成的结构体是8,这个问题更有点意思以后再说) 嗯,那么经过我的测试,这个结果是8个字节,说明啊 这个char & b这个东西啊 占了四个字节 ,这里我们就庆幸没有int型做测试吧;嗯现在弄清了内存方面的事情,就开始思考这个引用变量是个什么东西了,
接着,我们就来看看这个引用它究竟是什么东西,这里我们会对一段cpp代码的结果反编译成汇编来分析分析;
先来一个测试代码
int main()
{
int a=10;
int & b=a;
b=20;
return 0;
}
这么小,能干啥事啊,别担心,虽然这个玩意儿连头文件都没带,但是却能干大事啊 把这段代码编译链接成exe,然后我们学一会儿黑客(黑的是自己),分析一下这个程序的汇编成分;
_main proc near var_8= dword ptr -8
var_4= dword ptr -4
argc= dword ptr 8
argv= dword ptr 0Ch
envp= dword ptr 10h push ebp
mov ebp, esp
sub esp, 8
mov [ebp+var_4], 0Ah
lea eax, [ebp+var_4]
mov [ebp+var_8], eax
mov ecx, [ebp+var_8]
mov dword ptr [ecx], 14h
xor eax, eax
mov esp, ebp
pop ebp
retn
_main endp
这是啥玩意啊,看不懂啊,看不懂没关系,我们可以把上面那个cpp代码换成指针版本的;如下
int main()
{
int a=10;
int * b=&a;
*b=20;
return 0;
}
功能一样是吧,那我们也来反编译一下;
_main proc near var_8= dword ptr -8
var_4= dword ptr -4
argc= dword ptr 8
argv= dword ptr 0Ch
envp= dword ptr 10h push ebp
mov ebp, esp
sub esp, 8
mov [ebp+var_4], 0Ah
lea eax, [ebp+var_4]
mov [ebp+var_8], eax
mov ecx, [ebp+var_8]
mov dword ptr [ecx], 14h
xor eax, eax
mov esp, ebp
pop ebp
retn
_main endp
有没有发现,两个汇编代码居然是一模一样啊,应该没有一点不一样的;虽然不明白它们是什么意思,但是好厉害的样子,起码能够证明引用和指针在底层实现上是等价的,这也就解释了为什么问题1里面引用的内存是4个字节了(X86 架构哦);对于这两段汇编代码(其实是一样的) 如果感兴趣的话,我们可以聊一聊 慢慢的有种渐入佳境的感觉了,下面我们就来从逻辑上分析一下,为什么要有这么一种引用类型呢;
其实这个问题,不是我能回答的,因为c++又不是我发明的,我哪里知道, 但是呢我们可以从编程语言的历史上推测(这是一种科学的猜测方法) , c语言有一个强大的东西叫指针,它的功能强大,又有多种变种,。拿到一个指针,便能操作那块内存了, 但是呢 指针太强大了,容易出错啊,怎么办呢,c++就说咱们来封装一个这个指针吧,虽然不能灭了它,但咱惹不起总躲得起吧; 于是 就发明出引用这种东西,从使用角度上讲增加了许多易用性呢;比如说对int a;操作 指针要 int *pa=a; * pa=123;而引用就不用*
了,而且引用必须在定义的时候赋初值,否则报错,而指针就没错 甚至有些连警告都没有,想想看这多危险啊, 还有引用一经指定对象便不能更改 相当于一个const指针 ,所以我们可以认为引用是对const指针的一种封装 ,好了引用有了 那就灭掉指针吧,不行,因为c++有一种妥协性,怎么说呢,引用受限是为了防止指针使用出错,但是由于指针太强大了,在一些需要指针出现的场合(比如遍历)引用又不能胜任,所以就又保留了指针; 在对指针的封装方面,java做到了,它直接把指针封装成名字了,让人感觉不到指针的存在,完全抛弃了指针
, 那就不能姓c了 于是就叫java吧;
经过上面放分析,我们知道引用就是对const指针的封装,为什么要封装,当然是第一安全,第二快速;就像栈和队列是对链表的封装一样,链表那么强大的东西,封装出来两个小东西,c也一样, 其他语言就是在逻辑层面封装了c , 懂了c再搞这些东西,岂不是 小儿科 ,要是不懂c 不懂内存,那这些我感觉就得跟着感觉走了,理解起来就不是推测而是猜测了; 有人觉得我不懂这些东西也行啊 会用就行了,那这是建立在记忆而不是理解的基础上,等到一段时间不用,再回头来看,我觉得如果之前理解过还是要回忆的快; 所以每当听到有人说c简单
我就觉得莫名其妙 这些东西不都是c玩剩下 的么;
由底层和逻辑说开去--c++之引用的深入剖析的更多相关文章
- 由底层和逻辑说开去——c++之类与对象的深入剖析
类是什么,对象是什么, 这两个问题在各个c++书里面都以一种抽象的描述方式,给了我们近乎完美的答案,然后我好像就知道什么是类什么是对象了,但是当扪心自问,类在哪儿,对象在哪儿,成员方法在哪儿,成员变 ...
- [Objective-C] 从NSInteger说开去
在iOS开发过程中,我一直习惯于使用C语法里的基本类型,而很少用(除非必须使用)Foundation的数据类型.最近看了一些资料,发现自己这样写可能有风险,虽然目前没遇到过相关的问题,但这是非常需要注 ...
- (转)2019年 React 新手学习指南 – 从 React 学习线路图说开去
原文:https://www.html.cn/archives/10111 注:本文根据 React 开发者学习线路图(2018) 结构编写了很多新手如何学习 React 的建议.2019 年有标题党 ...
- JSP 生命周期 理解JSP底层功能的关键就是去理解它们所遵守的生命周期
JSP 生命周期 理解JSP底层功能的关键就是去理解它们所遵守的生命周期. JSP生命周期就是从创建到销毁的整个过程,类似于servlet生命周期,区别在于JSP生命周期还包括将JSP文件编译成ser ...
- 从Linux内核升级的必要性说开去
Linux内核更新超级频繁,可是有必要时刻升级吗?个人感觉没有必要,可是你要时刻关注新特性列表,然后把自己的内核升级到离最新版本号差一两个月公布的版本号而不是最新版本号.以保证稳定性,由于一两个月的时 ...
- Flask-分开Models解决循环引用
Flask-分开Models解决循环引用 在之前我们测试中,所有语句都在同一个文件中,但随着项目越来越大,管理起来有所不便,所以将Models分离.基本的文件结构如下 \—–app.py\—–mode ...
- 从《BLAME!》说开去——新一代生产级卡通真实感混合的渲染方案
<BLAME!>是Polygon Pictures Inc.(以下简称PPI)创业33周年以来制作的第一部CG剧场电影,故事来自于贰瓶勉的同名漫画作品(中文译名为<探索者>或者 ...
- 由SOAP说开去 - - 谈谈WebServices、RMI、RPC、SOA、REST、XML、JSON
引子: 关于SOAP其实我一直模模糊糊不太理解,这种模模糊糊的感觉表述起来是这样: 在使用web服务时(功能接口),本来我就可以通过安卓中固有的http类(使用http协议),来发送http请求,并且 ...
- 从一个Bug说开去--解决问题的思路,Linked Server, Bulk Insert, DataTable 作为参数传递
声名— 部分内容为杜撰,如有雷同,不胜荣幸! 版权所有,如要引用,请标明出处! 如果打赏,请自便! 1 背景介绍 最近一周在忙一个SQL Server 的Bug,一个简单的Bug,更新两张 ...
随机推荐
- java中访问mysql数据库中的表结构信息
package cn.hncu.meta; import java.sql.Connection;import java.sql.DatabaseMetaData;import java.sql.Re ...
- [转]Oracle hang分析
hanganalyze是ORACLE的一款性能诊断工具,这个款工具是从oracle 8.0.6开始可用,在oracle数据库出现严重的性能问题的时候它可以帮助你定位问题所在. 1.首先说说hangan ...
- linux内存查看
一般用free命令,显示整体内存使用状况: 第二行从OS角度,used包括内核+应用+buffers+cached使用的内存,buffers/cached是磁盘缓存的大小 第三行从应用角度,可用内存= ...
- 设计包含min函数的栈
stack<pair<int, int>> sta; void push(int x) { int min_i; if(sta.empty()) { min_i = x; } ...
- MYSQL5.5和5.6参数的差异
performance_schema 在 MySQL 5.6 中默认是开启的,但相关的很多参数相比 MySQL 5.5 却是降低了,例如 performance_schema 自动调整到 445 个表 ...
- CSS行高--line-height
遇到的问题:在css中,不理解line-height:1与line-height:1px的区别 发现的过程:最近在学做一个网站的过程中,设置两行文字之间的行高时需要用到line-height,发现了这 ...
- MVC中使用AuthorizeAttribute注意事项
代码调用顺序为:OnAuthorization-->AuthorizeCore-->HandleUnauthorizedRequest 如果AuthorizeCore返回false时,才会 ...
- U大师装系统
主要步骤 1. 若是ghost版本,直接使用智能快速装机版即可安装. 2.安装64位操作系统(iso文件) 1)下载系统地址 http://msdn.itellyou.cn/ . 2)制作好U盘启动, ...
- .NET微信支付(H5仅限公众号支付)
闲来无事,恰好有一个要用微信公众平台支付的功能,研究来研究去,就是要细心和多看腾讯提供的文档.当然有几个坑是很有必要说明一下的 公众号支付,这里统一叫H5支付,以下都是. 在做H5支付的时候,第一步就 ...
- OC第一天-Xcode、工程组成及运行状态
Xcode 中iOS工程模版: 1.Application类型: Master-detail Application. 可以构建树形结构导航模式应用,生成的代码中包含了导航控制器和表示图控制器.(表示 ...