zoukankan      html  css  js  c++  java
  • c++引用和指针的实现

    引用和指针有什么区别?引用在进程中是否会分配内存?
    
    C++ primer中说: 引用就是对象的另一个名字。
    C++ primer中说: 指针用于指向对象,保存的是另一个对象的地址。
    
    从字面意义上,感觉引用并没有分配内存,而指针是分配了内存的,于是写了个小程序进行测试。
    
    
    int main()
    {
            long val = 1;
            long &r_val = val;
            const long &const_r_val = val;
            const long &const_r_tmp = 123;
            long *p_val = &val; 
            printf("val                     address: 0x%lx
    ", &val);
            printf("r_val                   address: 0x%lx
    ", &r_val);
            printf("const_r_val             address: 0x%lx
    ", &const_r_val);
            printf("const_r_tmp             address: 0x%lx
    ", &const_r_tmp);
            printf("p_val                   address: 0x%lx
    ", &p_val);
            void *tmp;
            tmp = &r_val; 
            const void *const_tmp;
            const_tmp = &const_r_tmp;
            tmp = &p_val; 
            return 0;
    }
    采用g++编译得到如下结果:
    
    
    val                     address: 0x7fff7377ee48
    r_val                   address: 0x7fff7377ee48
    const_r_val             address: 0x7fff7377ee48
    const_r_tmp             address: 0x7fff7377ee50
    p_val                   address: 0x7fff7377ee40
    可以看出对引用取地址(&)跟变量取地址(&)都是得到同一个地址值,而对指针取地址(&)得到的是另外一个地址,好像引用真的没有分配内存,这是真的吗????
    
    其实上不然,从C++语义上说,引用就是对象的另一个名字,并没有具体的指定另一个名字的具体实现,根据编译器的不同,引用的实现也不一样。
    
    我们通过objdump –d a.out进行反编译可知:
    
    
    
    long val = 1;
    movq   $0x1,0xffffffffffffffe8(%rbp)//将立即数1复制给val所在的内存
    long &r_val = val;
    lea    0xffffffffffffffe8(%rbp),%rax//将val所在的内存地址赋值给rax
    mov    %rax,0xfffffffffffffff0(%rbp)//将rax赋值给r_val所在的内存
    long *p_val = &val;
    lea    0xffffffffffffffe8(%rbp),%rax//将val所在的内存地址赋值给rax
    mov    %rax,0xffffffffffffffe0(%rbp)//将rax赋值给p_val所在的内存
    我们可以看出实际上指针和引用的在g++编译器中的实现是一样的,既然分配了内存,为何&r_val == &val ?
    
    我们来继续看看反汇编代码:
    
    tmp = &r_val;
    mov    0xfffffffffffffff0(%rbp),%rax//将r_val变量中存的内存地址赋值给rax
    mov    %rax,0xfffffffffffffff8(%rbp)//将rax的值赋值给了tmp
    tmp = &p_val;
    lea    0xffffffffffffffe0(%rbp),%rax//将p_val的内存地址赋值给了rax
    mov    %rax,0xfffffffffffffff8(%rbp)//将rax的值赋值给了tmp
    对于取地址运算(&),g++编译器对于引用和其他变量的处理是不一样的,引用调用的汇编指令mov,得到引用所在内存存储的变量内存地址,而其他变量的取地址(&)运算调用的是汇编指令lea,得到变量本身的存储地址,于是有了引用不分配内存的假象。
    
    上述分析针对于linux下的g++编译器,传说在VC中进行编译会得到不同的结果,在debug编译下,引用是会分配内存的,而在release编译下,引用不分配内存,直接调用变量,有兴趣的童鞋可以去试试。
  • 相关阅读:
    ASP.NET Core 从入门到精通-资源收集导航
    【5分钟系列】计算机系统结构的定义
    C#反射与特性(九):全网最全-解析反射
    C#反射与特性(七):自定义特性以及应用
    C#反射与特性(六):设计一个仿ASP.NETCore依赖注入Web
    C#反射与特性(五):类型成员操作
    C#反射与特性(四):实例化类型
    C#反射与特性(三):反射类型的成员
    C#反射与特性(二):探究反射
    安卓TabLayout+ViewPager实现切页
  • 原文地址:https://www.cnblogs.com/zendu/p/4981446.html
Copyright © 2011-2022 走看看