c++11学习笔记(3)- 左值、右值和右值引用
1.左值和右值
什么是左值,什么又是右值呢?先看一个例子
int a = b + c;
这里的 a 就是左值, 而 b+c 就是右值。
C++标准中没有明确的定义左值和右值,通常意义上我们对于左值和右值做出如下规定。
- 可以取地址的、有名字的为 左值 。
- 不能取地址的、没有 名字的就为 右值 ,&(b+c) 无法编译通过,所以为右值。
右值有两个概念组成:将亡值和纯右值。
纯右值:用于辨识临时变量和一些不跟对象关联的值,比如,非引用的函数返回的临时变量的值为右值,一些运算表达式,如 1+2 产生临时变量的值也为右值;不跟对象关联的字面量也为右值如 2 、‘c’ 、true;类型转换的返回值,lambda表达式也为右值。
将忘值:右值引用相关的表达式,这些表达是通常是将要被移动的对象(移为他用),比如右值引用 T&& 的函数返回值,std::move 的返回值,转换为 T&& 转换函数的返回值。
2.右值引用
- 右值引用:对一个右值引用的类型,使用 T&& 表示。
下面就是一个右值引用的简单示例:
int b = 10, c = 20;
int a = b + c;
int& ac = a;
int&& bc = b + c;
std::cout << ac << std::endl;
std::cout << bc << std::endl;
输出结果为:
30
30
无论是左值引用还是右值引用,都必须立即初始化;因为引用本身并不具有绑定对象的内存,只是该对象的别名,左值是具体变量名的别名,右值是(匿名)变量名的别名。
3.右值引用的使用
1. 使用右值引用增长生命周期
我们首先来看一下下面的一个例子:
#include <iostream>
#include "stdlib.h"
class TestClass
{
public:
TestClass(int number = 0):m_Number(number){
std::cout << __FUNCTION__ << std::endl;
}
~TestClass() {}
int m_Number = 10;
};
TestClass func(void) {
TestClass testObj(20);
return testObj;
}
int main(int argc, char** argv)
{
TestClass && testClass = func();
std::cout << testClass.m_Number << std::endl;
system("pause");
return 0;
}
运行结果为:
TestClass::TestClass
20
可见在调用函数 func 时,只产生了一次对临时变量的拷贝构造调用
TestClass && testClass = func();
后 func() 的生命周期结束了,但是通过右值引用,增长了它的生命周期,只要 testClass 对象还“活着”,那么它的值就一直存活下去。
2. 右值引用接受的对象
- 通常右值引用是不能绑定左值的;
- 非常量左值只能接受非常量左值对他进行初始化;
- 常量左值是“万能”引用类型,它可以接受左值、常量左值、右值对它进行初始化
下表列出C++中所有引用类型可引用值得类型
引用类型 | 非常量左值 | 常量左值 | 非常量右值 | 常量右值 |
---|---|---|---|---|
非常量左值引用 | Y | N | N | N |
常量左值引用 | Y | Y | Y | Y |
非常量右值引用 | N | N | Y | N |
常量右值引用 | N | N | Y | Y |
我面看一下下面的例子:
const bool &justment = true;
使用右值,并为其续命
const bool justment = true;
右值在表达式结束后被销毁
上一篇: 右值引用和对象移动
下一篇: 理解C和C++中的左值和右值