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. 右值引用的使用

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 对象还“活着”,那么它的值就一直存活下去。


3.2 右值引用接受的对象
  • 通常右值引用是不能绑定左值的;
  • 非常量左值只能接受非常量左值对他进行初始化;
  • 常量左值是“万能”引用类型,它可以接受左值、常量左值、右值对它进行初始化

下表列出C++中所有引用类型可引用值得类型

引用类型非常量左值常量左值非常量右值常量右值
非常量左值引用YNNN
常量左值引用YYYY
非常量右值引用NNYN
常量右值引用NNYY

我面看一下下面的例子:

const bool &justment = true;

使用右值,并为其续命

const bool justment = true;

右值在表达式结束后被销毁

不会飞的纸飞机
扫一扫二维码,了解我的更多动态。

下一篇文章:c++11学习笔记(4)- 移动构造函数与移动语义