c++右值引用

1. 左值和右值

(1)两者区别:
  ①左值:能对表达式取地址、或具名对象/变量。一般指表达式结束后依然存在的持久对象。
  ②右值:不能对表达式取地址,或匿名对象。一般指表达式结束就不再存在的临时对象。
  
(2)右值的分类
  ①将亡值(xvalue,eXpiring value):指生命期即将结束的值,一般是跟右值引用相关的表达式,这样表达式通常是将要被移动的对象,如返回类型为T&&的函数返回值(如std::move)、经类型转换为右值引用的对象(如static_cast< T&& >(obj))、xvalue类对象的成员访问表达式也是一个xvalue(如Test().memberdata,注意Test()是个临时对象)
  ②纯右值(prvalue, PureRvalue):按值返回的临时对象、运算表达式产生的临时变对象、原始字面量和lambda表达式等。

   ![C++表达式分类图](https://img-blog.youkuaiyun.com/20180528163908909?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hlbGxvd29ybGRfcHR0/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70 ) [图 1-1]C++11表达式分类图

2. 右值引用和左值引用

(1)右值引用和左值引用
  ①右值引用和左值引用都是属于引用类型。无论是声明一个左值引用还是右值引用,都必须立即进行初始化。
  ②左值引用是具名变量/对象的别名,右值引用是匿名变量/对象的别名。
  ③左值和右值是独立于它的类型的,即左右值与类型没有直接关系,它们是表达式的属性。具名的右值引用是左值,匿名的右值引用是右值。如Type&& t中t是个具名变量(最简单的表达式),t的类型是右值引用类型,但具有左值属性。而Type&& func()中的返回值(是个表达式)是右值引用类型,但具有右值属性(因为是个匿名对象)。
  


这里写图片描述
[表 2-1]引用类型分类表

3.std::forward与std::move

std::move是无条件的转为右值引用,而std::forward是有条件的转为右值引用,更准确的说叫做Perfect forwarding(完美转发),而std::forward里面蕴含着的条件则是Reference Collapsing(引用折叠)。


move 用于指明转移语义,常见于传参数和返回值。move 用于提示编译器,这里可以是转移语义,否则编译器会保守的使用复制语义。
—————————————————————避免拷贝耗资源——————————————————————-

4.C++测试代码
#include <iostream>
#include <vector>
#include <typeinfo>
void func(int& i)
{
    std::cout<< __PRETTY_FUNCTION__ <<" : " << typeid(i).name()<<std::endl;
}

void func(int&& i)
{
    std::cout << __PRETTY_FUNCTION__ << " : " << typeid(i).name() <<std::endl;
}

void func2(const int& i)
{
    std::cout << __PRETTY_FUNCTION__ << " : " << typeid(i).name() <<std::endl;
}

void l_func(int &i) 
{
      std::cout << __PRETTY_FUNCTION__ << " : " << typeid(i).name() <<std::endl;
}

void r_func(int&& i)
{
        std::cout << __PRETTY_FUNCTION__ << " : " << typeid(i).name() <<std::endl;
}
//__PRETTY_FUNCTION__是linux宏
template<class T>
void wrapper(T&& x)
{
    func(std::forward<T> (x));      //forward完美转发,有条件转为右值引用
    func(std::move(x));             //move无条件的转为右值引用
}

int main()
{
    int a =10;
    const int c = 20;
    std::cout<< "##########左值与右值 Test##########"<<std::endl;
    func(a);            //非常量左值
    func(20);           //非常量右值

    //l_func(10);       //10不可以作为一个左值传递
    //r_func(a);        //a不可以作为一个右值传递
    //int &&d = 20;     //常量右值
    //
    std::cout<< "##########forward与move Test##########" <<std::endl;
    wrapper(a);         
    wrapper(20);        

    std::cout<< "##########常引用 Test##########" <<std::endl;
    //常引用万能类型,用于拷贝语义
    func2(a);           //非常量左值
    func2(c);           //常量左值
    const int& d = 20;  //常量右值
    func2(20);          //非常量右值

    std::cout<<"Test d : "<<d<<std::endl;
    return 0;
}

运行结果:


这里写图片描述

本文前两段来自 : 作者 : 浅墨浓香 | 链接 : https://www.cnblogs.com/5iedu/p/7698710.html
本文第三段来自 : 作者:蓝色 | 链接:https://www.zhihu.com/question/34544004/answer/59104471

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值