对C++中引用概念的一些思考。
如何理解引用与指针的关系
语言语义
引用不是指针(与指针无关),而是对象本身(的别名),对引用的任何操作都是对被引用变量的操作。
底层实现
引用内部通常通过指针实现。
以下分别从语言级别和底层实现进行分析:
C++标准关于引用的说明(语言、语义)
-
原文
https://isocpp.org/wiki/faq/references
Even though a reference is often implemented using an address in the underlying assembly language, please do not think of a reference as a funny looking pointer to an object. A reference is the object, just with another name. It is neither a pointer to the object, nor a copy of the object. It is the object. There is no C++ syntax that lets you operate on the reference itself separate from the object to which it refers.
-
翻译
即使经常使用底层汇编语言中的地址来实现引用,也请不要将引用视为指向对象的有趣指针。引用是对象,只是带有另一个名称。它既不是指向该对象的指针,也不是该对象的副本,它是对象。没有C ++语法可让您对引用本身和引用对象进行单独操作。
注:语言标准不需要任何特定的机制,只要行为符合,每个实现都可以自由地以任何方式执行。
引用的原理(实现)
C++源程序
//定义变量
double a = 20.0;
//定义引用
double& b = a;
//定义指针
double* c = &a;
汇编角度:计算机访问内存中的数据,全部通过地址访问。所谓的变量a是对地址的标记,
在代码生成目标文件时,使用地址代替了所有的a,因此目标文件中不存在变量名a(变量a不占用内存)。
VS反汇编
//定义变量
double a = 20.0;
/*
013E18D2 movsd xmm0,mmword ptr [__real@4024000000000000 (013E7BD0h)]
013E18DA movsd mmword ptr [a],xmm0
*/
//定义引用
double& b = a;
/*
013E18DF lea eax,[a]
013E18E2 mov dword ptr [b],eax
*/
//定义指针
double* c = &a;
/*
013E18E5 lea eax,[a]
013E18E8 mov dword ptr [c],eax
*/
分析汇编代码
-
定义变量
double a = 20.0; /* 013E18D2 movsd xmm0,mmword ptr [__real@4024000000000000 (013E7BD0h)] 013E18DA movsd mmword ptr [a],xmm0 */
-
将双精度浮点数20.0存放在寄存器xmm0中。
-
将xmm0的数据存放在以a为地址的内存单元(8字节,64位)。
-
-
定义引用
double& b = a; /* 013E18DF lea eax,[a] 013E18E2 mov dword ptr [b],eax */
-
将a的地址赋值给寄存器eax。
-
将eax中的数据存放在以b为地址的内存单元(双字型,4字节,32位)。
-
-
定义指针
double* c = &a; /* 013E18E5 lea eax,[a] 013E18E8 mov dword ptr [c],eax */
-
将a的地址赋值给寄存器eax。
-
将eax中的数据存放在以c为地址的内存单元(双字型,4字节,32位)。
-
结论
- 如上,引用与指针的汇编代码相同,这说明在VC中引用内部通过指针实现(自身是常量的指针),并且引用只存在于编译阶段。
- 引用占用的内存空间为4个字节(见
dword ptr [b],eax
),也可定义含有引用类型的成员的类来验证。
一些补充
编译器对于
引用b
的解释将自动转换为*b
,故所有对引用b
的操作都是对变量a
的操作。例如:&b 被编译器解释为 &(*b) ,即&b == &a。
附:指针与引用的区别
指针 | 引用 | |
---|---|---|
内存 | 实体,必须分配内存(4字节) | 变量别名,(内存分配见底层实现) |
初始化 | 定义时可不初始化,指向可变 | 定义时必须初始化,绑定实体对象(不可变),不能为NULL |
多级 | 一级指针/多级指针 | 一级引用 |
自增 | 指向下一个空间 | 引用的变量(对象)+1 |
sizeof | 指针本身的大小 | 指向变量(对象)的大小 |
访问方式 | 间接访问 | 直接访问 |
作为参数 | 传递指针的地址 | 传递变量(对象)的地址 |
底层实现 | 通过指针 |
注:指针使用前应做类型检查,避免野指针。