目录

重学C++:引用和指针


常见的坑

  1. &*在不同的上下文里面其含义并不相同,因此完全可以当成不同的符号看待

    1
    2
    3
    4
    5
    6
    
    int i = 42;
    int &r = i;    // &在类型名后出现,是声明的一部分,表明r是一个引用
    int *p;        // *在类型名后出现,是声明的一部分,表明p是一个指针
    p = &i;        // &在表达式中出现,是取地址符
    *p = 43;       // *在表达式中出现,是解引用符
    int &r2 = *p;  // &是声明的一部分,*是解引用符
    
  2. 指针可以用0进行初始化成空指针,但是不可以用0赋值。

  3. 指针之间使用==来比较时,如果结果是true,对应多种情况:

    • 都是空指针
    • 都是同一个地址
      • 都指向同一个对象
      • 一个指针指向某一个对象,另一个指针指向另一对象的下一地址

必须要理解的点

  1. 引用和指针——都可以用于间接访问对象

    引用 指针
    复合类型
    表示符号 & *
    含义 变量的别名 变量在内存中的地址
    初始化和赋值时是否需要类型匹配 必须匹配(除常量引用) 必须匹配(除void*和指向常量的指针)
    是否需要初始化 必须初始化 无需初始化
    可否重新绑定其他变量 不可以 可以
    可否嵌套定义 不可以 可以

    引用:

    • 引用只能绑定在对象上,不能绑定在字面量或者表达式上。
    • 引用只是原有对象的别名,并非对象,因此不可以定义引用的引用。
    • 定义引用时并不开辟新的内存空间,因此不可以定义引用的指针。

    指针:

    • 指针本身就是一个对象,能执行的操作自由度远超过引用。

      • 可以实现嵌套定义,即指针的指针。

      • 可以实现指针的引用。

        1
        2
        3
        4
        5
        6
        
        int i = 42;
        int *p;         // p是int型指针
        int *&r = p;    // r是指针p的引用,从r开始自右向左读,&表明r是一个引用,引用的是指针,指针指向的类型是int
        
        r = &i;         // r是p的别名,即给p赋值为i的地址,即令p指向i
        *r = 0;         // r是p的别名,对r解引用即对p解引用,即将p所指向的地址处变量的值赋值为0
        
    • 指针初始化和赋值时需要使用&运算符取得对象的地址。

    • 指针值的情况:

      1. 指向一个对象。
      2. 指向紧邻对象所占空间的下一个位置。
      3. 空指针,没有指向任何对象。
      4. 无效指针,除上述情况之外。

      对第4种无效指针的操作是未定义的,后果无法预计。

      2、3两种值虽然有效,但是因为没有指向任何对象,所以对其操作的后果同样无法预计。

  2. void*眼中内存空间仅仅是内存空间,并不能访问内存空间中的对象。

建议

  1. 初始化所有的指针,并且在对象定义完成之后再定义指向它的指针。

  2. 避免使用0NULL初始化空指针,应该使用nullptr

  3. 在使用指针之前检查其是否为nullptr

  4. 记住赋值改变的永远是等号左侧的对象。

  5. 面对复杂的指针或引用的声明语句时,从变量名开始自右向左阅读来弄清楚其真实含义。