C++11:左值右值左值引用右值引用有什么区别?
Posted 木大白易
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++11:左值右值左值引用右值引用有什么区别?相关的知识,希望对你有一定的参考价值。
左值(lvalue)和右值(rvalue)
左值(lvalue):locator value,存储在内存中、有明确的的地址(可寻址)的数据
能够取地址,有名字的值就是左值
//左值引用
int a=10;
int &a1=a;//正确,a为左值类型,因为可以我们找到他的地址
int &a=10;//错误,左值引用不能引用一个右值类型的常量,(10是常量,常量为右值)
编译器允许我们对左值建立引用,但不允许对右值建立引用。除非使用常量左值引用操作右值:
int num = 10;
const int &b = num;
const int &c = 10;
也就是说常量左值引用即可以操作左值,也可以操作右值。
右值(rvalue):read value, 不能取地址,无名字的值就是右值。
举个例子:
int a = b+c, a 就是左值,其有变量名为a,通过&a可以获取该变量的地址;
表达式b+c、函数int fun()的返回值是右值,在其被赋值给某一变量前,我们不能通过变量名找到它,&(b+c)这样的操作则不会通过编译。
//右值引用
int &&a=10;//正确,右值引用一个右值类型
a = 100;
cout << a << endl;//100
int var = 10;
int&& var1 = var;//错误,因为无法将右值引用绑定到左值上
//右值引用绝对不能引用左值类型的,加上const也不行,这点是和左值引用不同的地方
const int&& var1 = var//照样报错,加上const也不行
//非引用返回的函数返回的都是右值,引用返回的函数返回的是左值
int fun1()
int &fun2()
int main()
int& z = fun1();//左值引用,报错
const int& z1 = fun1();//正确
int&& z2 = fun1();//正确
int& z = fun2();//左值引用,正确
const int& z1 = fun2();//延长生命期的左值引用,正确
int&& z2 = fun2();//报错,右值引用不能绑定左值
const int&& z2 = fun2();//报错
常量右值引用:
const int&& a = 10;//编译器不会报错
但这种定义出来的右值引用并无实际用处:
一方面,右值引用主要用于移动语义和完美转发,其中需要有修改右值的权限;
另一方面,常量右值引用的作用就是引用一个不可修改的右值,这些工作完全可以交给常量左值引用。
引用类型 | 可以引用的值类型 | 使用场景 | |||
---|---|---|---|---|---|
非常量左值 | 常量左值 | 非常量右值 | 常量右值 | ||
非常量左值引用 | Y | N | N | N | 无 |
常量左值引用 | Y | Y | Y | Y | 常用于类中构建拷贝构造函数 |
非常量右值引用 | N | N | Y | N | 移动语义、完美转发 |
常量右值引用 | N | N | Y | Y | 无实际用途 |
纯右值和将亡值
C++98中的右值就是纯右值,纯右值指的是临时变量值,不跟对象关联的字面量值
- 临时变量值:非引用返回的函数返回值、表达式等。
- 不跟对象关联的字面量值:例如true、2、"Hello World"等。
C++11对C++98中的右值进行了扩充。在C++11中右值又分为纯右值(prvalue,Pure Rvalue)和将亡值(xvalue,eXpiring Value)。其中纯右值的概念等同于我们在C++98标准中右值的概念,指的是临时变量和不跟对象关联的字面量值;
将亡值则是C++11新增的跟右值引用相关的表达式,这样表达式通常是将要被移动的对象(移为他用),比如:
- 返回右值引用T&&的函数返回值
- std::move的返回值
- 转换为T&&的类型转换函数的返回值
将亡值可以理解为通过“盗取”其他变量内存空间的方式获取到的值。 在确保其他变量不再被使用、或即将被销毁时,通过“盗取”的方式可以避免内存空间的释放和分配,能够延长变量值的生命期。
一般情况下,右值引用是不能引用左值的,但是可以使用std::move()函数将左值强制转换为右值:
int a;
int &&r1 = c; // 编译失败
int &&r2 = std::move(a); // 编译通过
#include <iostream>
#include <vector>
#include <string>
#include <utility>
using namespace std;
class A
public:
A()
a = 666;
cout << "构造A" << endl;
A(const A&a)
cout << "拷贝构造A" << endl;
~A()
cout << "析构A" << endl;
private:
int a;
;
int main(void)
int a = 6;
int &&b = std::move(a);
cout << "b = "<<++b << endl;//b=7
cout << "a = "<<a << endl;//a=7
string s = "hello";
vector<string> vec;
//调用常规的拷贝构造函数,新建字符串,拷贝数据
vec.push_back(s);
cout << "在拷贝之后:"<< s << endl;
//调用移动构造函数,掏空了s
vec.push_back(std::move(s));
cout << "在移动之后:" << s << endl;
A aa;
vector<A> vec_A;
vec_A.emplace_back(aa);
//cout << "移动构造:" << endl;
//调用移动构造函数,掏空了s
//vec.emplace_back(std::move(aa));
return 0;
推荐阅读
C++11 左值、右值、右值引用详解
c++ 之 std::move 原理实现与用法总结
以上是关于C++11:左值右值左值引用右值引用有什么区别?的主要内容,如果未能解决你的问题,请参考以下文章