码迷,mamicode.com
首页 > 编程语言 > 详细

【C/C++】【类和对象】左值(引用)和右值(引用)

时间:2020-07-21 09:32:08      阅读:61      评论:0      收藏:0      [点我收藏+]

标签:fun   清空   形式   标准库   错误   不能   重点   amp   strong   

左值和右值

  • 左值:能用在赋值语句等号左侧的东西;能够代表一个地址;
  • 右值:不能作为左值的值就是右值,右值不能出现在赋值语句等号的左侧;

结论

  1. C++的表达式,要么是左值,要么是右值,不能能两者都不是;
  2. 左值有的时候能够被当做右值使用;
int i = 10;
i = i + 1;	//i是个左值,不是右值,虽然它出现等号右边
//i用在等号右边的时候,i有一种右值属性;不是右值;
//i用在等号左边的时候,用的是i代表的内存中的地址,i有一种左值属性;
//一个左值,他可能给同时具有左值属性和右值属性

用到左值的运算符有哪些:

  1. 赋值运算符

    int a;
    cout << a = 4  << endl;
    (a = 4) = 8; //整个赋值语句的结果是左值;
    
  2. 取地址 &

    int a  = 5; //变量a是个左值		
    &a; // 
    
  3. 容器中的下标/迭代器

    string str = "hello world!";
    str[0]; 
    vector<int>::iterator iter;
    iter++;
    iter--;
    
  4. 通过判断一个运算符在一个字面值上能不能操作,可以判断运算符是否用到的是左值;

左值表达式、右值表达式

  1. 左值表达式当成左值;左值代表一个地址,所以左值表达式的求值结果,就得是一个对象,就得有地址;求值结果为对象的表达式,不代表一定是左值,具体再分析;
  2. 右值表达式当成右值;

总结:

  1. 左值,赋值运算符等号左边的东西;代表一个地址;
  2. 右值,代表赋值运算符右边的东西;代表一个值;

引用分类

三种形式的引用

  1. 左值引用(绑定到左值)

    int value = 10;
    int &ref_val = value;
    ref_val = 13; // value = 13;
    
  2. const引用(常量引用),也是左值引用,不希望改变值的对象;

    int value = 10;
    const int &ref_val = value;
    //ref_val = 18; 不可修改
    
  3. 右值引用,绑定到右值:是个引用,主要用于临时对象;

    int &&ref_right_value = 3; //绑定到一个值上
    ref_right_value = 5;
    

左值引用

将变量绑定到左值上;

  • 没有空引用的说法,所以左值引用初始化的时候就绑定左值;
  • 引用必须初始化
  • 左值引用必须绑定到左值,不能绑定到右值
  • const引用可以绑定到右值;相当于系统产生一个临时变量;将常引用绑定到临时变量上;
    int a = 1;
    int &b{a}; //b绑定到a
    
    //int &c; 错误,引用必须要初始化
    
    //int &c = 1; 错误,左值引用必须绑定到左值,不能绑定到右值
    
    const int &c = 1; //const引用可以绑定到右值
    //相当于系统产生一个临时变量,将c绑定到临时变量中;
    

右值引用

引用右值,也就是说,绑定到右值;必须是绑定到右值的引用;通过&&

  • &&右值引用,用来绑定一些即将销毁的或者是一些临时对象上;

  • 右值引用也是引用,可以把右值引用理解成一个对象的名字;

    int &&ref_right_value = 3; 
    ref_right_value = 5;
    
  • 能绑定到左值引用上的,一般都不能绑定到右值;

  • 右值引用也绑定不到左值上;

    string str_te{"Hello world"};
    string &ref_str_1{str_te}; //可以,左值引用绑定到左值;
    //string &ref_str_2{"Hello world"}; 不可以,左值引用不能绑定到临时变量; 临时变量被系统当做右值
    const string *const_ref_str{"hello world"}; //可以,创建一个临时对象,绑定到左值上,const不仅可以绑定到右值,还可以执行到string的隐式类型转换并将所得到的的值放到string临时变量中
    
    //string &&ref_right_1{str_te}; //右值引用不能绑定到一个左值;
    string &&ref_right_2{"hello world"}; //可以,绑定到一个临时变量,临时变量的内容“hello world”
    
    int i = 10;
    int &ri_1 = i; //正确,左值引用
    int &&ri_2 = i; //错误,不能将右值引用绑定到左值上;
    int &&ri_3 = i * 100; //正确,右值引用绑定到右值
    int &r4 = i * 100; //左值引用不能绑定到右值
    const int &r5 = i * 100; //const引用可以绑定到右值;
    
    

总结

  1. 返回左值引用的函数,连同赋值,下标,解引用和前置递增递减运算符,都是左值表达式的例子;可以将一个左值引用绑定到这类表达式上;
  2. 返回非引用类型的函数,连同算术,关系,位以及后置递增运算符,都生成右值;不能将一个左值引用绑定到这类表达式上,但是可以将一个const的左值引用或者一个右值引用绑定到这类表达式上;

前置++和后置++的区别

  • 前置++

    
    ++i; //左值表达式,++i直接给变量i+1,然后返回i本身
    //因为i是变量,所以可以被赋值;
    
    int i = 100;
    (++i) = 199; //i = 199;
    int &r1 = ++i; //成功绑定左值 r3就是i的别名;
    
    
  • 后置++

    
    i++; //右值表达式,i++先产生一个临时变量,记录i的值用于使用的目的,i的值被使用之后,再给i+1,接着返回这个临时变量
    
    //(i++) = 199; //错误 右值无法赋值;
    
    int i = 1;
    int &&ref = i++; //成功绑定右值; 此后ref的值和i没有关系
    
    // int &r2 = i++; //左值引用不能绑定到右值表达式上
    

重点

  • ref虽然是右值引用(绑定到了右值),但是ref本身是左值(要把ref看成是一个变量);因为它在等号左边;并且左值引用可以绑定到ref这个左值上;

  • 所有变量看成左值,因为他们有地址,用右值引用无法绑定;

  • 任何函数中的形参都是左值;

    void func(int &&v); //w是右值引用,但w本身是左值;
    
  • 临时对象都是右值;

右值引用的引入目的

  • C++11引入的,&&,代表一种新数据类型;
  • 通过将拷贝对象变成移动对象来提高程序运行效率;
  • 移动对象如何发生:
    • 移动拷贝构造函数
    • 移动赋值运算符
    • 参数类型是右值引用
  • 拷贝对象如何发生
    • 拷贝构造函数
    • 拷贝赋值运算符
    • 参数类型是左值引用

std::move函数

  • C++11标准库的新函数;std::move:移动;实际函数没有做移动操作;
  • std::move的作用:将一个左值强制转换成一个右值;右值引用可以绑定上去了;
int i = 10;
int &&ref = std::move(i);
i = 20; //i的值改变,ref的值也变量; ref代表i;


int &&ri = 100; //ri是左值
int &&re = std::move(ri); 


//string的移动构造函数做了哪些事情
// 1. 将str清空; 2. 给def分配内存 3.将str的内容移动到def
string str = "hello world";
const char* q = str.c_str(); //q是str实际所占内存
string def = std::move(str); //=会调用string的移动构造函数,导致str中的内容移动到def中
const char* p = def.c_str(); //p是def实际所占内存

string str = "hello world";
std::move(str); //单独执行 str内容没空,只是将str转成右值;


string str = "hello world";
string &&def_r = std::move(str); //def_r右值引用 绑定到str上;
//建议:使用了std::move之后,不要用str了;

【C/C++】【类和对象】左值(引用)和右值(引用)

标签:fun   清空   形式   标准库   错误   不能   重点   amp   strong   

原文地址:https://www.cnblogs.com/Trevo/p/13343862.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!