分析一下 C++ 里面的引用类型(例如:int &r = a;
)中的 r
变量是否占用内存空间呢?是否和 int *p = &a;
中的 p
变量一样占用内存空间呢?
本文将给出答案。
直接看一个简单的例子:
#include <iostream>
using namespace std;
int main(void)
{
int a = 6;
int &r = a;
int *p = &a;
int x = r;
return 0;
}
接着我们通过 g++ testref.cpp -o testref -g
来编译之后,用gdb来加载它,看看 a
, r
, p
, x
的地址分别是多少:
上图中 a
的地址为 0x7fffffffe208
,用取地址符去获取 r
地址,值和 a
是一样的,其实,用 &
符号是不能获取到引用类型变量的地址的,因为引用类型的变量本身只是另一个对象的别名,用可感知的方式描述,就是它仅仅是一个名字而已,对它的任何操作都是相当于对另一个对象的操作,所以这个取地址操作也是一样。
但是,我们接着往下看,p
的地址是 0x7fffffffe218
,和 a
的地址刚刚相差了 16 字节,接着看 x
的地址是 0x7fffffffe20c
,这个地址正好是 a
的地址 0x7fffffffe208 + 4
, 而 a
是 int
型,变量本身占用 4 字节,正常情况下, x
的地址应该是 p
的地址 0x7fffffffe218 + 8
,这里 +8
是因为我的机器是 64 位的机器,所以指针类型占用 8 字节。现在这种情况应该是编译器做了优化,把 x
的放到了 a
的后面,同样的,x
的下一个变量的起始地址应该是 0x7fffffffe20c + 4
= 0x7fffffffe210
,这个地址和 p
之间刚好差了 8 个字节,也就是一个指针变量的地址,所以答案就很明显了。
即,我们现在可以猜测,r
是占用内存空间,并且占用的大小和指针变量相同大小。但是我们上面用gdb也看不了 r
的实际地址,所以这也只能是猜测,只是看似合理的猜测而已。
为了证明这个猜测,我们继续把可执行文件反汇编出来看看:objdump -d testref
得到的结果如下:
00000000004006cd <main>:
4006cd: 55 push %rbp
4006ce: 48 89 e5 mov %rsp,%rbp
4006d1: c7 45 e8 06 00 00 00 movl $0x6,-0x18(%rbp) # int a = 6; a的地址 0x18
4006d8: 48 8d 45 e8 lea -0x18(%rbp),%rax
4006dc: 48 89 45 f0 mov %rax,-0x10(%rbp) # int &r = a; r的地址 0x10
4006e0: 48 8d 45 e8 lea -0x18(%rbp),%rax
4006e4: 48 89 45 f8 mov %rax,-0x8(%rbp) # int *p = &a; p的地址 0x8
4006e8: 48 8b 45 f0 mov -0x10(%rbp),%rax # 下面两行是为了后面的赋值做准备
4006ec: 8b 00 mov (%rax),%eax
4006ee: 89 45 ec mov %eax,-0x14(%rbp) # int x = r; x的地址 0x14
4006f1: b8 00 00 00 00 mov $0x0,%eax
4006f6: 5d pop %rbp
4006f7: c3 retq
我把对应处,都写在上面的注释里了。
所以,现在可以得到结论:引用类型的变量会占用内存空间,占用的内存空间的大小和指针类型的大小是相同的。 从上面的汇编代码可以看出,虽然引用是一个对象的别名,但是在汇编层面,和指针是一样的。
2015.07.29