• 4 引用的本质


    1 引用的意义

    • 引用作为变量别名而存在,因此在一些场合可以代替指针

    • 引用相对于指针来说具有更好的可读性实用性

    • swap 函数的实现对比

      //指针方法
      void swap(int* a,int* b)
      {
          int t = *a;
          *a = *b;
          *b = t;
      }
      
      //引用方法
      void swap(int& a,int& b)
      {
          int t = a;
          a = b;
          b = t;
      }
      
    • 注意:函数中的引用形参不需要初始化,它的初始化发生在函数调用的时候

    2 特殊的引用

    • const 引用

      • 在 C++ 中可以声明 const 引用

      • const Type& name = var;

      • conts 引用让变量拥有只读属性

        int a = 4;
        const int& b = a;
        int* p = (int*)&b;  //等价于对变量a取地址
        
        b = 5;  //error: assignment of read-only reference 'b'
        *p = 5;  //正确,修改变量a的值
        
    • 当使用常量const 引用进行初始化时,C++ 编译器会为常量值分配空间,并将引用名作为这段空间的别名

      const int& b = 1;
      
      int* p = (int*)&b;
      
      b = 5;  //error: assignment of read-only reference 'b'
      *p = 5;  //正确: 修改变量a的值
      
      • 使用常量对 const 引用初始化后将生成一个只读变量
    • 问题:引用有自己的存储空间么?

      • 有!

      • Demo

        #include <stdio.h>
        
        struct TRef
        {
            char& r;
        };
        
        int main(int argc, char *argv[])
        { 
            char c = 'c';
            char& rc = c;
            TRef ref = { c };
            
            printf("sizeof(char&) = %d
        ", sizeof(char&));  //1
            printf("sizeof(rc) = %d
        ", sizeof(rc));  //=> sizeof(c) = 1
            
            printf("sizeof(TRef) = %d
        ", sizeof(TRef));  //0?
            printf("sizeof(ref.r) = %d
        ", sizeof(ref.r));  //=> sizeof(c) = 1
        
            return 0;
        }
        
      • 运行结果

        sizeof(char&) = 1
        sizeof(rc) = 1
        sizeof(TRef) = 4
        sizeof(ref.f) = 1
        

    3 引用的本质

    • 引用在 C++ 中的内部实现是一个指针常量

      Tyep& name;
      void f(int& a)
      {
          a = 5;
      }
      
      //等价于
      Type* const name;
      void f(int* const a)
      {
          *a = 5;
      }
      
    • 注意

      • C++ 编译器在编译过程中用指针常量作为引用的内部实现,因此引用所占用的空间大小与指针相同
      • 从使用的角度,引用只是一个别名,C++ 为了实用性而隐藏了引用的存储空间这一细节
    • 引用的存储空间

      • Demo

        #include <stdio.h>
        
        struct TRef
        {
            char* before;
            char& ref;
            char* after;
        };
        
        int main(int argc, char* argv[])
        {
            char a = 'a';
            char& b = a;  //1)取变量a的地址 2)将a的地址赋值给b对应的4个字节的内存空间中去
            char c = 'c';
        
            TRef r = {&a, b, &c};
        
            printf("sizeof(r) = %d
        ", sizeof(r));
            printf("sizeof(r.before) = %d
        ", sizeof(r.before));
            printf("sizeof(r.after) = %d
        ", sizeof(r.after));
            printf("&r.before = %p
        ", &r.before);
            printf("&r.after = %p
        ", &r.after);
        
            return 0;
        }
        
      • 编译运行

        sizeof(r) = 12
        sizeof(r.before) = 4
        sizeof(r.after) = 4
        &r.before = 0xbf8a300c
        &r.after = 0xbf8a3014
        
    • 函数引用返回:返回局部变量的引用/指针可能会造成内存泄漏

      • Demo

        #include <stdio.h>
        
        int& demo()
        {
            int d = 0;
            
            printf("demo: d = %d
        ", d);
            
            return d;  //error: 返回局部变量的引用 <=> return &d
        }
        
        int& func()
        {
            static int s = 0;
            
            printf("func: s = %d
        ", s);
            
            return s;  //返回静态局部变量 => 正确,静态变量不会随着函数调用的返回而被摧毁
        }
        
        int main(int argc, char* argv[])
        {
            int& rd = demo();
            int& rs = func();
            
            printf("
        ");
            printf("main: rd = %d
        ", rd);
            printf("main: rs = %d
        ", rs);
            printf("
        ");
            
            rd = 10;
            rs = 11;
            
            demo();
            func();
            
            printf("
        ");
            printf("main: rd = %d
        ", rd);
            printf("main: rs = %d
        ", rs);
            printf("
        ");
            
            return 0;
        }
        
      • 编译

        test.cpp: In function ‘int& demo()’:
        test.cpp:5:9: warning: reference to local variable ‘d’ returned [-Wreturn-local-addr]
             int d = 0;
                 ^
        
      • 运行

        demo: d = 0
        func: s = 0
        
        main: rd = 13209588  <=>rd 等价于一个野指针
        main: rs = 0
        
        demo: d = 0
        func: s = 11
        
        main: rd = 132095588
        main: rs = 11
        
  • 相关阅读:
    Web前端开发的一点记录
    关于表情符号与UTF-8的探讨
    微信公众号H5游戏本地搭建环境和调试(花生壳+wampserver+微信公众号测试号)
    ES6下的数组去重
    关于JS数组循环删除元素出现下标不对的问题
    好资源收藏
    ftp 操作,支持断点续传或者继续下载。
    推荐 greenrobot eventbus,简化安卓开发,提高安卓维护性,优化安卓性能
    T4模板TextTemplatingFileGenerator和TextTemplatingFilePreprocessor区别
    .net使用FluentValidation进行服务端验证。
  • 原文地址:https://www.cnblogs.com/bky-hbq/p/13695492.html
Copyright © 2020-2023  润新知