zoukankan      html  css  js  c++  java
  • C/C++-左值、右值及引用

    C和C++中定义了引用类型(reference type),存在左值引用(lvalue reference)。而在C++11中,新增了右值引用(rvalue reference)这一概念, 虽然个人感觉右值引用用处不大,但在此一并讨论。

    1.左值and右值

    首先,我们讨论左值和右值两个概念。
    左值(lvalue):一个标识非临时性对象的表达式。通常来说,可以将程序中所有带名字的变量看做左值。
    右值(rvalue):相对的,右值标识是临时性对象的表达式,这类对象没有指定的变量名,都是临时计算生成的。
    考虑以下代码:

    vector<string> arr(3);
    const int x = 2;
    int y;
    int z = x + y;
    string str = "foo";
    vector<string> *ptr = &arr;
    

    在上述代码中,arr, str, y, z等都是左值,x也是一个左值,且他不是一个可修改的左值;而类似于2, x+y这类临时(没有专属变量名)的值则是右值。

    2.引用

    我们可以这样理解引用:一个引用是它所引用对象的同义词,是其另一个变量名。
    看这样一段代码:

    #inclulde <stdio.h>
    
    int main()
    {
        int x = 5;
        int & y = x;
        printf("引用y = %d
    ", y);
        return 0;
    }
    

    运行结果如下:

    (1)左值引用
    左值引用的声明是通过在某个类型后放置一个符号&来进行的。前文代码中的int & y = x;便是一个左值引用。
    需要注意的是,在定义左值引用时,=右边的要求是一个可修改的左值。因此下面几种左值引用都是错误的:

    #include <stdio.h>
    
    int main()
    {
        const int x = 5;
        int y = 1;
        int z = 1;
        int & tmp1 = x;     // ERROR:x不是一个可修改的左值
        int & tmp2 = 5;     // ERROR:5是一个右值
        int & tmp3 = y + z; // ERROR:y+z是一个右值
        return 0;
    }
    

    编译运行,报错如下:

    (2)右值引用
    类似于左值引用,右值引用便是对右值的引用,它是通过两个&&来声明的。

    #include <stdio.h>
    
    int main()
    {
        int && x = 5;
        printf("x = %d
    ", x);
        return 0;
    }
    
    

    运行结果如下:

    引用和指针的区别
    我们知道,指针是在内存中存放地址的一种变量,cpu能够直接通过而变量名访问唯一对应的内存单元,且每个内存单元的地址都是唯一的。
    而变量名和引用,都可以看做内存的一个标签或是标识符,计算机通过是否符合标识符判断是否为目标内存,而一个内存可以有多个标识符

    3.左值引用的用途

    因为目前右值引用用途不大,故此处仅列举较为常见的左值引用用途
    (1)作为复杂名称变量的别名
    我们可以写出类似如下的语句:

    auto & whichList = theList[myHash(x, theList.size())];
    

    可以看到,我们用简短的whichList代替了其原本复杂的名称,这能够简化我们的代码书写。
    (2)用于rangeFor循环
    设想我们希望通过rangeFor循环使一个vector对象所有值都增加1,下面的rangeFor循环是做不到的、

    for (auto x : arr)   // x仅相当于每个元素的拷贝
        ++x;
    

    但我们可以通过使用引用达到这一目的

    for (auto & x : arr)
        ++x;
    

    (3)避免复制大的对象
    假定有一个findMax函数,它返回一个vector中最大的元素。若给定vector存储的是某些大的对象时,下述代码中的x拷贝返回的最大值到x的内存中:

    auto x = finaMax(vector);
    

    在大型的项目中这显然会增大程序的开销,这时我们可以通过引用来减小这类开销

    auto & x = findMax(vector);
    

    类似的,我们在处理函数返回值的时候也可以使用传引用返回。但是要注意,当返回的是类中私有属性时,传回的引用会导致外界能够对其修改。
    (4)参与函数中的参数传递
    在C和C++的函数中,addSelf(int x)这类函数对直接传入的参数进行修改并不会改变原有参数的值。而有时我们希望能够实现类似swap(int a, int b)这类能够修改原参数的函数时,我们可以通过1.传入指针2.传入引用实现
    swap函数的实现是一个很好的例子

    #include <stdio.h>
    
    void swap_non(int, int);    // 直接传入参数 
    void swap_p(int *, int *);  // 传入指针
    void swap_r(int &, int &);  // 传入引用
    
    int main()
    {
        int a = 1;
        int b = 2;
        printf("直接传入参数时:
    ");
        swap_non(a, b);
        printf("a = %d, b = %d
    ", a, b);
        printf("传入指针时:
    ");
        swap_p(&a, &b);
        printf("a = %d, b = %d
    ", a, b);
        printf("传入引用时:
    ");
        swap_r(a, b);
        printf("a = %d, b = %d
    ", a, b);
        return 0;
    }
    
    void swap_non(int a, int b)
    {
        int temp = a;
        a = b;
        b = temp;
    }
    
    void swap_p(int * a, int * b)
    {
        int temp = *a;
        *a = *b;
        *b = temp;
    }
    
    void swap_r(int & a, int & b)
    {
        int temp = a;
        a = b;
        b = temp;
    }
    

    运行结果如下:

    可以看到,只有在传入指针和传入引用时变量才真正交换。

    直接传入参数传入指针仍不理解的可以看这篇博客,在此不再描述。

    4.std::move和std::swap

    前面我们讨论3.(3)时,谈到可以使用引用来减少复制产生的内存开销。
    考虑这样一种情况,在进行元素交换时,我们通常使用一个缓存变量temp来临时保存数据;而对temp直接进行=的赋值操作时,实际上temp复制了一次原有对象的内存,但我们需要只是对象之间的移动而不是复制,而C++STL中的std::move函数便可以达成这一操作。
    这可能有些抽象,让我们通过例子来看看:

    void swap(vector<string> & x, vector<string> & y)
    {
        vector<string> temp = std::move(x);
        x = std::move(y);
        y = std::move(temo);
    }
    

    上述例子是C++STL中std::swap的源码之一,相信它很好的示范了std::move是如何使用的,而在源码中使用,也足以说明它的高效。

  • 相关阅读:
    css3在不同型号手机浏览器上的兼容一览表
    android 常见分辨率(mdpi、hdpi 、xhdpi、xxhdpi )及屏幕适配注意事项
    web app iphone4 iphone5 iphone6 iphone6 Plus响应式布局 适配代码
    用sql查询当天,一周,一个月的数据
    VS2010 生成Xml格式的注释文档
    VS XML注释
    css3 box-sizing属性
    CSS技巧(一):清除浮动
    使用Windows Server 2003搭建一个asp+access网站
    如何在Windows Server 2003搭建Windows+iis+asp+access环境
  • 原文地址:https://www.cnblogs.com/Bylight/p/10530274.html
Copyright © 2011-2022 走看看