C++11 左值和右值

01 左值和右值的基本概念

  • 左值
    一般来说,可以取地址的,有名字的就是左值。如:

    int a = 10;								// a 左值; 10 右值
    int b = a + 10;  						// b 左值; a + 10 右值
    
  • 右值
    不能取地址,没有名字的就是右值。右值又分为以下两种:

    • 将亡值
      将被移动的对象,如返回右值引用 T&& 的函数的返回值;std::move 的返回值。
    • 纯右值
      返回类型非引用的函数返回的临时变量的类型;运算符表达式的值;不跟对象关联的字面值常量。
  • 左值引用和右值引用

    int n = 10;
    int & l_n = n;							// 左值引用
    int && r_n = std::move(l_n);			// 右值引用
    

03 引用的新规则

  • 引用折叠规则
    如果间接的创建一个引用的引用,将会造成这些引用的折叠

    • 所有的右值引用折叠到右值引用上仍然是一个右值引用

      T && && => T &&
      
    • 所有的其他类型的引用的引用都将变成左值引用

      T & & => T &
      T & && => T &
      T && & => T &
      

    引用折叠的根本原因是 C++中禁止 reference to reference

    可以简单的认为所有包含左值引用的引用的引用都会折叠成左值引用

  • 右值引用的特殊类型推断原则
    当将一个左值传递给一个参数是右值引用的模板函数时,编译器会推断模板参数的类型为实参的左值引用

    template<typename T>
    void func(T &&) {}
    
    int n = 10;
    func(10);
    
  • 可以通过 static_cast 显式的将一个左值转换成一个右值

    int n = 10;
    int &qln = n;
    // int && qrn = qln;					// 无法将右值引用绑定到左值
    int && qrn = static_cast<int &&>(qln);	// Ok
    

04 std::move

C++11 基于安全的原因具名参数即便是右值引用也不会被认定为右值,必须使用 std::move 来获取右值

void isRValue(const int& num) { std::cout << "left ref" << std::endl; }
void isRValue(const int&& num) { std::cout << "right ref" << std::endl; }

int main()
{
    int&& a = 5;

    isRValue(a);                    	// left ref
    isRValue(std::move(a));         	// right ref
}

sstd::move 作用将参数无条件的转换成的右值引用

标准库中的 move 定义

template<class _Ty>
_NODISCARD constexpr remove_reference_t<_Ty>&&
    move(_Ty&& _Arg) noexcept
{	// forward _Arg as movable
    return (static_cast<remove_reference_t<_Ty>&&>(_Arg));
}

其中 std::move函数的参数 _Ty && 是一个指向模板类型的右值引用,由于模板中的右值引用可以接收左值和右值,因此 std::move函数的参数既可以是一个右值也可以是一个左值
而且 std::move 函数实际上是通过 static_cast 返回右值的因此其本质上和 static_cast<_Ty &&>(_Arg) 没有区别。

05 std::forward

std::forward 作用返回该显式实参类型的右值引用,以保证参数在传递过程中保持其属性,又被称为完美转发
std::forward 不仅可以保持左值和右值属性不变,还同时可以保持 const, l_reference, r_reference, validate 等属性不变。

void isRValue(const int& num) { std::cout << "left ref" << std::endl; }
void isRValue(const int&& num) { std::cout << "right ref" << std::endl; }

int main()
{
    int&& a = 5;

    isRValue(a);                    	// left ref  实参类
    isRValue(std::forward<int>(a));     // right ref 实参类型为 int&&
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值