右值引用
在本篇你将看到:
- 什么是左值?什么是右值?
- 什么是左值引用?什么是右值引用?
- 什么是移动构造?
1、左值和右值
左值和右值是C语言的概念,但是C语言并没有给出严格的区分方式,一般认为:可以放在等号左边的或者能够取地址的称为左值,只能放在等号右边的,或者不能取地址称为右值。但是也不一定完全正确。
咱们先来看一段代码:
int main()
{
int a = 10;
int b = 20;
//a和b都是左值,b既可以在=的左侧,也可以在右侧,如下:
a = b;
b = a;
//说明:左值既可以放在=的左侧,也可以放在=的右侧
const int c = 30;
c = a; //编译报错,c为const 常量,只允许读不允许修改
//因为可以对c取地址,因此c严格的来说不算是左值,如下:
cout << &c << endl;
//编译失败,因为b+1的结果是一个临时变量,没有具体名称,不能取地址,因此为右值,如下:
b + 1 = 20;
system("pause");
return 0;
}
看到这里,你是否对左值和右值有一点点感觉?其实可以这么理解:对于一个表达式,凡是对其取地址(&)操作可以成功的都是左值,否则就是右值
需要注意的是:临时对象是右值
总结:
1、普通类型的变量,因为有名字,可以取地址,都认为是左值
2、const修饰的常量,不可修改,制度类型的,理论按照右值俩对待,但是因为其可以取地址,C++11认为它是左值
3、如果表达式的运行结果是一个临时对象或者对象,认为是右值
4、如果表达式运行结果或者单个变量是一个引用,则认为是左值
2、左值引用和右值引用
了解左值和右值之后,我们再来说说左值引用和右值引用。我们知道C++11是不能对右值进行修改,但是右值引用的出现打破了这一格局,它允许我们获取右值的引用并修改它。
看一个代码秒懂:
int main()
{
int a = 10;
//普通类型只能引用左值,不能引用右值,如下:
int& ra1 = a; //ral为a的别名
//int& ra2 = 10; //编译失败,因为10是右值
//const引用既可以引用左值,也可以引用右值,如下:
const int& ra3 = 10;
const int& ra4 = a;
system("pause");
return 0;
}
一句话概括:普通类型只能引用左值,不能引用右值,但是const引用既可以引用左值,也可以引用右值
右值引用的类型为:类型 && a=被修改的对象。如下:
int main()
{
//10本来是纯右值,本来是一个符号,没有具体空间
//右值引用变量r1在定义过程中,编译器产生了一个临时变量,r1实际引用的是临时变量
int &&r1 = 10;
r1 = 100;
int a = 10;
//int&& r2 = a; //编译失败,因为右值引用不能引用左值
int&& r3=move(a); //但是加上move之后可以引用左值
return 0;
}
总结:
- 左值引用和右值引用都是给对象取别名
- 左值通常是:可以被修改的对象
- 右值通常是:常量,表达式的返回值
- 左值可以引用左值
- const左值可以引用右值
- 右值可以引用右值
- 右值引用可以用move来引用左值
3、拷贝构造函数的局限性
(为什么突然提到拷贝构造函数,因为移动构造可以解决拷贝构造的不足)在这里我定义了一个类Test,然后在main函数里面调用Test的构造函数和拷贝构造函数初始化Test 的对象t。
解释一下,可以看到,这个例子中调用了两次拷贝构造,一次是类外调用Test的构造函数,返回给Function函数的时候,一次是初始化Test对象t的时候。
其实这两个临时对象并没有什么意义,构造结束就会被销毁,也就是一个将亡值,在拷贝构造中进行了不必要的拷贝,在以上代码还好,我只开了一百个int的空间,那万一是几百万个甚至是几亿个,效率就会更低。好像有点道理,那我们应该怎么办?看后面
4、移动构造函数
移动构造是想,既然你(临时对象)已经是个将亡值了,那我直接那你的内存拿来,你也就不用再开空间慢慢的把你的数据拷贝给我,也就是说直接上述代码中我们直接把_a所指向的那块内存拿过来,然后把之前的100个整型值给复制过来。其实这就是移动构造函数的思想。
关于移动构造函数,就是一种构造函数,不过它所接受的参数是一个本类对象的右值引用,对于以上例子,它的移动构造函数如下:
Test(Test &&rhs):_a(rhs._a)
{
rhs._a=nullptr;
}
在移动构造的初始化列表的时候,我们只做了一个浅拷贝,_a(rhs._a),将rhs对象已经申请的内存占用了,同时将rhs的指针赋值为nullptr,这就避免了拷贝构造函数内存复制导致的效率问题。
以上就是关于C++右值引用的信息,笔者也是才学不久,哪里有问题,希望广大网友提出,一定虚心接受