C++基础语法-引用的本质

2020-02-02  本文已影响0人  码无不至

引用的本质

本篇文章我们深入探讨下引用存在的价值和引用的本质,先来看看引用和指针的两个经典案例,交换两个变量:

//通过传入变量地址达到交换的目的
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;
}

int main() {
    int a = 10;
    int b = 20;
    swap(a, b);
    cout << "a is " << a << endl;
    cout << "b is " << b << endl;
    return 0;
}

引用是C++的特性,C没有,通过上述列子以及通过种种迹象表明跟指针有某种联系,下面我们先来看看引用占用的内存大小。

 int age = 10;
 int &rage = age;
 cout << sizeof(rage) << endl; //4
 cout << sizeof(age) << endl;  //4

这样验证似乎看不出端倪,都是输出4,因为引用是变量的别名,这两个sizeof只跟变量有关,没关系我们将引用放到结构体里面,然后用sizeof结构体对象来验证,定义一个包含引用的结构体:

struct Person {
    int age;
    const int &heigh = 10; //引用必须初始化,这里就声明一个常引用
};

然后我们输出下这个结构体大小:

Person p = {10};
cout << sizeof(p) << endl; //16

结构体大小竟然为16,int占四个字节,引用不可能占12个字节,而根据内存对齐原则,引用占用8个字节,对齐后才是16个字节,8个字节跟指针占用字节大小一样。不禁让人想看看指针和引用的汇编代码到底怎么处理的?接下来我们通过断点查看反汇编代码:

//指针
int age = 18;
int *p = &age;
*p = 20;
//以上代码转为反汇编代码如下:
pushq  %rbp
movq   %rsp, %rbp
xorl   %eax, %eax
movl   $0x0, -0x4(%rbp)
movl   $0x12, -0x8(%rbp)//将rbp-0x8地址此时的值赋值为18,占四个字节
leaq   -0x8(%rbp), %rcx //将rbp-0x8地址赋值给rcx,占8个字节
movq   %rcx, -0x10(%rbp) //这里将rcx赋值到rbp-0x10地址中,占8个字节
movq   -0x10(%rbp), %rcx //将rbp-0x10地址又赋值到rcx,占8个字节
movl   $0x14, (%rcx)  //将0x14也就是20赋值到rcx指向的地址中,占4个字节
popq   %rbp
retq

以上是指针修改age,并且它的反汇编代码,对部分汇编代码进行了解释和说明,我们再来看看引用的代码:

//引用
int age = 18;
int &rAge = age;
rAge = 20;
//通过断点转为反汇编代码如下:
pushq  %rbp
movq   %rsp, %rbp
xorl   %eax, %eax
movl   $0x0, -0x4(%rbp)
movl   $0x12, -0x8(%rbp)
leaq   -0x8(%rbp), %rcx
movq   %rcx, -0x10(%rbp)
movq   -0x10(%rbp), %rcx
movl   $0x14, (%rcx)
popq   %rbp
retq

通过以上反汇编带的阅读和对比,结果发现它们的汇编代码一模一样,目前为止,可以得出一个结论:引用的本质就是指针,引用是弱化了的指针,它比指针更安全。指针地址如果不是const修饰是可以修改指向的内存,而引用只能指向开始初始化的变量的地址,不能修改。相当于被const修饰的指针一样。

int age = 10;
int *page = &age;
int &rage = age; //相当于int* const page = &age;

引用在C++中十分常用,通过对引用大量的学习,以及通过反汇编对其本质研究,希望同学们学得愉快,学得爽,如有任何疑问,欢迎留言,祝进步!

上一篇下一篇

猜你喜欢

热点阅读