C++中 value category & move

原来我也只知道C++中有左值和右值,通过今天的学习才知道,C++中不光有左值和右值。

C++中有5种值类别,lvalue, rvalue, glvalue, xvalue, prvalue

在这里插入图片描述

  • lvalue: 左值
  • rvalue: 右值
  • glvalue: generalized lvalue, 广义左值
  • xvalue: expiring lvalue, 将亡值
  • prvalue: prue rvalue, 纯右值

看到这些不要害怕,我们一点点来。

首先我们看下最熟悉的lvalue.

lvalue

左值是有标识符,可以取地址的表达式。 比如说:

  • 变量,函数名,类的数据成员名

    这些都是变量名嘛

  • 返回左值引用的表达式,如 ++x, x = 1, cout << " "

  • 字符串字面值,如"hello world"

值得注意的是,&, reference 其实是左值引用,我们在调用函数时,传递的参数是左值,编译器就会匹配函数参数是左值的那一个函数。

一个常量只能绑定到常左值引用,比如:

const int a = 1;
// int& b = a;  // 编译不过
const int& c = a;

prvalue

纯右值,是没有标识符,不可取地址的表达式,一般称之为临时对象

  • 非引用类型的表达式,如x++, x+1, make_shared(42)
  • 除字符串字面值之外的字面值,如 42, true

在C++11之前,右值可以绑定到常左值引用的参数,但是不可以绑定到非 常左值引用。 如:

// int& a = 1; // 编译不过
const int& a = 1;

在C++11,引入了右值引用,&&。这时我们就可以右值绑定到常右值引用,或者是非常右值引用了。

int&& a = 1;
const int&& b = 1;

引入一种额外的引用类型当然增加了语言的复杂性,但也带来了很多优化的可能性。由于 C++ 有重载,我们就可以根据不同的引用类型,来选择不同的重载函数,来完成不同的行为。

void f(int& a) {
   
    cout << "int&" << endl;
}

void f(int&& a) {
   
    cout << "int&&" << endl;
}

int main(int argc, char const* argv[])
{
   
    int a = 1;
    f(a);  // a 是一个左值,变量名
    f(1);  // 数字1是一个右值
    return 0;
}

输出:

int&
int&&

那f内的a是左值还是右值呢? 都是左值,因为他们都是一个变量名。类型右值引用的变量是一个左值

xvalue

将亡值,也是一个右值

标准库里有一个move函数,std::move,它的作用是把一个左值引用强制转换成一个右值引用,并不改变其内容。

我们可以把move的返回值看成一个有名字的右值,为了跟无名的纯右值相区别,C++就把这种表达式叫做xvalue,xvalue也是不能取地址的。


插播一个生命周期

一个变量的生命周期在超出作用域时结束。如果一个变量代表一个对象,当然这个对象的生命周期也在那时结束。

那临时对象(prvalue)呢?

C++ 的规则是:一个临时对象会在包含这个临时对象的完整表达式估值完成后、按生成顺序的逆序被销毁,除非有生命周期延长发生。

我们先看一个没有生命周期延长的基本情况:

class shape {
   
public:
    virtual ~shape() {
   }
};

class circle : public shape {
   <
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值