C++引用的本质

404joker404 Lv3

转自 https://blog.csdn.net/lws123253/article/details/80353197#:~:text=%E5%BC%95%E7%94%A8%E5%BA%95%E5%B1%82%E6%98%AF%E6%8C%87%E9%92%88%E5%B8%B8%E9%87%8F

c++中“引用”的底层实现原理详解

初学c++中的“引用”这一概念的时候,很多人都是懵的,大家大概都会产生这样的疑问?
什么是引用?
引用占用内存吗?

于是,为了验证你的猜想,你可能会写出下面这样的代码来验证:

    #include<iostream>
    using namespace std;
    int main()
    {
        int  a = 1;
        int&  b = a;
        cout << "a:address->" << &a << endl;
        cout << "b:address->" << &b << endl;
        getchar();
        return 0;
    }

运行结果:

    a:address->0031FD54
    b:address->0031FD54

我们会发现,引用b的地址和变量a的地址一样。于是,有人猜想是不是说变量a和引用b本身就是一个东西。所以同样的,引用本身所占内存就是变量a的内存。

首先对于这个说法,肯定是不正确的

至于为什么不正确,我们接下来会以底层原理为大家解释。

什么是引用

为了看看引用的底层究竟是怎样实现的,我决定写一个简短的代码,然后反汇编(vs编译环境在调试模式下,右键鼠标菜单->反汇编)看一看。

    #include<iostream>
    using namespace std;
    int main()
    {
        int x=1;
        int &b=x;
        return 0;
    }

我们再看下转汇编后的汇编代码:

    9:       int x = 1; 	//源代码 
    00401048   mov         dword ptr [ebp-4],1	//反汇编代码  
    10:      int &b = x; 	//源代码
    0040104F   lea         eax,[ebp-4]  		//反汇编代码
    00401052   mov         dword ptr [ebp-8],eax//反汇编代码

在这里解释下这三行反汇编代码:

    mov dword ptr [ebp-4],1 //把1赋值给ebp(栈底指针)-4的地址
    lea eax,[ebp-4] //把ebp-4的地址赋值给寄存器eax        
    mov dword ptr [ebp-8],eax //把寄存器eax里的值赋值给ebp-8的这块地址

上述三行代码的作用就是将1赋值给x,然后将x的地址赋值给了引用b。
而在内存中,它是这样的:
这里写图片描述
注意:因为栈在内存中是由高地址向低地址增长的
通过底层的分析,我们不难理解引用的本质就是所引用对象的地址。

建议:有兴趣的同学可以了解一下常见的汇编指令,对于了解代码底层原理有很大的帮助。
##引用占用内存吗
通过上面的分析,我们得出了引用本身存放的是引用对象的地址,通俗点理解就是引用就是通过指针来实现的,所以,应用所占的内存大小就是指针的大小。
##引用的地址
在最开始,我们写过一段代码来测试引用的地址,发现引用的地址和变量的地址是一样的。但是,在后面对引用的底层分析后发现,它本身又存放的是变量的地址,即引用的值是地址,那么这不是很冲突吗?

事实上, b的地址我们没法通过&b获得,因为编译器会将&b解释为:&(*b) =&x ,所以&b将得到&x。也验证了对所有的b的操作,和对x的操作等同。

那么问题来了,我们如何才能获得引用的地址呢?
我们看下面这段代码:

    #include<stdio.h>
    #include <iostream>  
    using namespace std;
    int main()  
    {  
        int x = 1;  
        int y = 2;  
        int &b = x;  
        printf("&x=%x,&y=%x,&b=%x,b=%x\n",&x,&y,&y-1,*(&y-1));  
        return 0;
    }


输出:
&x=12ff7c,&y=12ff78,&b=12ff74,b=12ff7c

%x表示以16进制的形式输出

不知道看到这里大家明白了没有,引用b的地址我们可以间接通过&y-1来得到b的地址,从而得到b的值:*(&y-1) 从结果可以知道,b的值即x的地址,从而可以知道,从底层实现来看,引用变量的确存放的是被引用对象的地址,只不过,对于高级程序员来说是透明的,编译器 屏蔽了引用和指针的差别。

所以

    引用在底层通常是通过指针实现的,但从编程的角度看,引用并不占用额外的内存空间,它只是所引用对象的一个别名。
    指针本身占用一定的内存空间,用于存储所指向对象的地址。

说明:大家在实践的时候,这里的x和y的地址不一定是连续的,因为这跟地址分配有关。

我们这里的研究只是为了通过这段代码为大家更好地解释引用和指针的区别。

如果还不明白,我们继续看这段代码变量的内存布局图:

a

最后要注意一点的是:引用就是引用,指针就是指针,引用不代表指针,一定不要混淆。

  • 标题: C++引用的本质
  • 作者: 404joker404
  • 创建于 : 2024-10-05 21:48:52
  • 更新于 : 2024-10-05 22:49:53
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论