C++ | 引用

C111111 / 2023-07-31 / 原文

引用 &

  • 使用引用

    int b = 33, &a = b;
    b = 17;
    cout << a; // 打印a为17
    

    使用引用声明变量类似于指针,声明的变量会同被引用的变量绑定,修改任何一方的数据都会使另一方的数据也改变。使用上的区别在于使用引用不需要*,引用可以理解为一个别名。

  • 在函数中使用引用传递参数

    将参数设置为引用的作用是:调用函数时参数不进行拷贝,而是直接使用传入的变量,在函数中的所有修改都会应用于该变量。

    • 基本类型

      int myAge = 15;
      void newYear(int &age){age++;}
      

      使用引用传递变量,调用函数newYear(myAge)myAge变量将会被改变

    • 复杂数据结构(如类,结构体)

      vector<int> v(100);
      void sum(vector<int> &v){/* 求和 */}
      

      函数参数的传递都是拷贝一份副本,将副本传递进去(如基本类型),所以如果不使用引用,程序将会复制整个vector,大大浪费了时间以及内存

    • 指针

      引用跟指针的功能很类似,都是为了能在函数中修改传入的参数。

      相同点:下面代码中调用函数后m变量存储的都是demo的地址,m中的height也都被修改了

      void setHeight(member &m, int height){m.height = height;}
      setHeight(demo, h);
      void setHeight(member *m, int height){m->height = height;}
      setHeight(&demo, h);
      

      不同点:

      • 对于引用形式,虽然m变量存储的是被引用对象的地址,但对程序员来讲,m就是作为demo的一个别名,使用m就等于使用demo,而不是使用demo的地址。

      • 对于指针,假如以下面形式调用函数:

        member *p = &demo;
        setHeight(p, h);
        

        传入变量p作为参数后,p与m的值都是&demo,即p和m都指向demo的地址,使用他们都能修改demo中的数据,但他们是两个不同的变量,即&p&m是不同的,在函数中修改m变量并不能作用于p变量。本质上,传递指针参数也是拷贝变量。

        对于下面代码:

        void applyForMemory(node *n){
            n = new node[10];
        }
        node *p;
        applyForMemory(p);
        

        这段代码是不起作用的,n申请了空间,只是将n指向的地址改成了新空间的地址,但p的指向没有改变。这段代码反而造成了内存泄漏。

        void applyForMemory(node *&n){
            n = new node[10];
        }
        node *p;
        applyForMemory(p);
        

        将指针作为引用形式传递,可理解为变量n即p。给n申请了空间,n的指向被修改了,p也被修改。

      总而言之,单纯传递指针参数实际上是存在两个变量:作为参数传入的变量(p)和在函数中使用的变量(n),他们的值都是同一个地址,他们指向同一个地方(demo),所以能够在函数中使用n变量来修改demo变量的数据;但他们还是两个变量,具有不同的地址,在函数中修改n的值(即修改n的指向)并不能作用与p,p的指向依旧是demo。

      而将指针作为引用来传递可以简单理解为只有一个变量:p,把n当作p的别名,那么修改了n的值(指向)自然p的指向也被修改了;当然,实际上n与p还是两个变量,p存储着demo的地址,而n中存储的是p的地址,编译器会自动将对n的操作转换成对p的操作,所以看起来他们就是同一个变量。

  • 函数返回值使用引用

    将返回值的引用返回,即不进行复制然后返回副本

    当然,如果使用引用作为返回值,那么是无法返回在函数中声明的变量的。因为那些变量在栈中,随着函数的结束运行,栈的内存被释放,该变量也会被释放。

    node* & AVLTree::getRoot(){return this->root;}
    node* & root = tree.getRoot();