左值、右值、左值引用、右值引用

 

左值、右值、左值引用、右值引用

  411人阅读  评论(0)  收藏  举报
  分类:

一、c++中的左值和右值

误区:左值位于等号左边,右值位于等号右边。

C++11中的定义:左值表达式表示的是一个对象的身份(在内存中的位置),而右值表达式表示的是对象的值(内容)。

左值和右值都是针对表达式而言的,左值是持久的,右值是短暂的:左值在表达式结束后仍然存在,右值在表达式结束后会被销毁。

区分左值和右值的方法:看能不能进行取地址操作,若能,则为左值,否则为右值。

注意:在需要右值的地方可以用左值来代替,但是不能把右值当成左值(也就是位置)使用。

例子:

若有如下定义:

[cpp]  view plain  copy
  1. int a = 10;  
  2. int b = 20;  
  3. int *p = &a;  
  4. vector<int> T;  
  5. T.pushback(1);  
  6. string s1 = “Hello”;  
  7. string s2 = "World";  
  8. const int &m =1;  

问:

a,b,a+b,a++,++a,p,*p,T[0],100,string("Hello"),s1,s1+s2,m分别是左值还是右值?

答:

a,b是变量,变量可以看做只有运算对象而没有运算符的表达式,变量表达式都是左值。事实上,变量a,b均是长久的,在生命周期结束才被销毁,且我们能够对a,b进行取地址操作。故a,b均为左值。

a+b是临时变量,在该表达式结束时就被摧毁,且不能对其进行取地址操作,因此a+b为右值。

a++的作用机理是先将a的值拷贝到一个临时变量中,然后将这里临时变量加1,最终返回的是这个临时变量,因此a++为右值。

++a的作用机理是在原数据a上直接加1,最终返回的是原来的那个对象(只不过值加了1),因此++a为左值。

p表示的是指向a的指针,它也是长久的,并且我们能对其进行取地址操作,得到的是指向a的指针的地址。因此p为左值。

*p与a等价,也为左值。

T[0]返回容器T中第一个元素的引用,这是一个int型变量,是长久的,并且能对其进行取地址操作,因此T[0]为左值。

100是个常量,在使用过后就会销毁,并且不能对其进行取地址操作,因此100为右值。

string("Hello")与100类似,也是个常量,在使用过后就会销毁,并且不能对其进行取地址操作,因此string("Hello")为右值。

s1是string类型的变量,与a,b类似,是长久的,并且可以进行取地址操作。因此s1是左值。

s1+s2与a+b类似,是临时变量,在表达式结束就被摧毁,并且不能对其进行取地址操作。因此s1+s2是右值。

m是一个常量类型1的const左值引用,但它本身是一个变量表达式,因此m是左值。

二、左值引用和右值引用

左值引用符:&

右值引用符:&&

左值引用不能绑定到右值对象上,右值引用也不能绑定到左值对象上。

由于右值引用只能绑定到右值对象上,而右值对象又是短暂的、即将销毁的。也就是说右值引用有一个重要性质:只能绑定到即将销毁的对象上。

左值、右值引用的几个例子:

[cpp]  view plain  copy
  1. int i = 42;//如前所述,i是一个左值对象  
  2. int &r = i;//正确,左值引用绑定到左值对象i  
  3. int &&rr = i;//错误,右值引用绑定左值对象  
  4. int &r2 = i * 42;//错误,如前所述i*42是临时变量,是右值,而&r2是左值引用  
  5. int &&rr2 = i * 42;//正确,右值引用绑定右值对象  

注意:以上绑定规则有一个例外,如果左值引用是const类型的,则其可以绑定到右值对象上。

[cpp]  view plain  copy
  1. const int &r3 = i * 42;//正确,我们可以将一个const的引用绑定到一个右值对象上  

对于一个左值,若想使用其右值引用,我们可以用move函数:

[cpp]  view plain  copy
  1. int &&rr3 = std::move(rr1);//正确,显式使用rr1的右值引用  

一、c++中的左值和右值

误区:左值位于等号左边,右值位于等号右边。

C++11中的定义:左值表达式表示的是一个对象的身份(在内存中的位置),而右值表达式表示的是对象的值(内容)。

左值和右值都是针对表达式而言的,左值是持久的,右值是短暂的:左值在表达式结束后仍然存在,右值在表达式结束后会被销毁。

区分左值和右值的方法:看能不能进行取地址操作,若能,则为左值,否则为右值。

注意:在需要右值的地方可以用左值来代替,但是不能把右值当成左值(也就是位置)使用。

例子:

若有如下定义:

[cpp]  view plain  copy
  1. int a = 10;  
  2. int b = 20;  
  3. int *p = &a;  
  4. vector<int> T;  
  5. T.pushback(1);  
  6. string s1 = “Hello”;  
  7. string s2 = "World";  
  8. const int &m =1;  

问:

a,b,a+b,a++,++a,p,*p,T[0],100,string("Hello"),s1,s1+s2,m分别是左值还是右值?

答:

a,b是变量,变量可以看做只有运算对象而没有运算符的表达式,变量表达式都是左值。事实上,变量a,b均是长久的,在生命周期结束才被销毁,且我们能够对a,b进行取地址操作。故a,b均为左值。

a+b是临时变量,在该表达式结束时就被摧毁,且不能对其进行取地址操作,因此a+b为右值。

a++的作用机理是先将a的值拷贝到一个临时变量中,然后将这里临时变量加1,最终返回的是这个临时变量,因此a++为右值。

++a的作用机理是在原数据a上直接加1,最终返回的是原来的那个对象(只不过值加了1),因此++a为左值。

p表示的是指向a的指针,它也是长久的,并且我们能对其进行取地址操作,得到的是指向a的指针的地址。因此p为左值。

*p与a等价,也为左值。

T[0]返回容器T中第一个元素的引用,这是一个int型变量,是长久的,并且能对其进行取地址操作,因此T[0]为左值。

100是个常量,在使用过后就会销毁,并且不能对其进行取地址操作,因此100为右值。

string("Hello")与100类似,也是个常量,在使用过后就会销毁,并且不能对其进行取地址操作,因此string("Hello")为右值。

s1是string类型的变量,与a,b类似,是长久的,并且可以进行取地址操作。因此s1是左值。

s1+s2与a+b类似,是临时变量,在表达式结束就被摧毁,并且不能对其进行取地址操作。因此s1+s2是右值。

m是一个常量类型1的const左值引用,但它本身是一个变量表达式,因此m是左值。

二、左值引用和右值引用

左值引用符:&

右值引用符:&&

左值引用不能绑定到右值对象上,右值引用也不能绑定到左值对象上。

由于右值引用只能绑定到右值对象上,而右值对象又是短暂的、即将销毁的。也就是说右值引用有一个重要性质:只能绑定到即将销毁的对象上。

左值、右值引用的几个例子:

[cpp]  view plain  copy
  1. int i = 42;//如前所述,i是一个左值对象  
  2. int &r = i;//正确,左值引用绑定到左值对象i  
  3. int &&rr = i;//错误,右值引用绑定左值对象  
  4. int &r2 = i * 42;//错误,如前所述i*42是临时变量,是右值,而&r2是左值引用  
  5. int &&rr2 = i * 42;//正确,右值引用绑定右值对象  

注意:以上绑定规则有一个例外,如果左值引用是const类型的,则其可以绑定到右值对象上。

[cpp]  view plain  copy
  1. const int &r3 = i * 42;//正确,我们可以将一个const的引用绑定到一个右值对象上  

对于一个左值,若想使用其右值引用,我们可以用move函数:

[cpp]  view plain  copy
  1. int &&rr3 = std::move(rr1);//正确,显式使用rr1的右值引用  

猜你喜欢

转载自blog.csdn.net/groundhappy/article/details/69675666