左值与右值(lvalue&rvalue)
左右值来源于C语言,原意是为了方便记忆:左值可以位于赋值语句的左侧,右值则不能。但是在C++中,左右值的区分没有那么简单,还存在 许多例外的情况,如:
const int a =1; //a是左值但不可修改
那么,到底如何区分左右值,我的理解是,一个左值表达式首先必须要能使用其地址,所以不能是常量表达式,计算式,字面常量。可以简单归纳为:
此外,左右值的使用可以总结出几点规律:
左值引用与右值引用(lvalue reference&rvalue reference)
左值引用,就是正常的引用,需要注意的是const引用,
int i=1; int &a = i; //正确,i的左值引用 int &b =2; //错误,左值引用不能绑定右值 const int &c = 3; // 正确,特殊情况,可以理解为临时创建了一个左值,然后引用
右值引用,是C++11引入的新类型,所谓右值引用就是必须绑定到右值的引用。通过&&而不是&来获得右值引用。右值引用有一个重要的性质----只能绑定到一个将要销毁的对象。因此,可以自由地将一个右值引用的资源”移动”到另一个对象中。右值引用有两个主要用途:
Rvalue引用支持移动语义的实现,这可以显着提高应用程序的性能。移动语义使您可以编写将资源(例如动态分配的内存)从一个对象转移到另一个对象的代码。移动语义之所以起作用,是因为它使资源能够从程序中其他地方无法引用的临时对象中转移。要实现移动语义,通常需要为类提供一个移动构造函数以及一个可选的移动赋值运算符(operator =)。源为右值的复制和赋值操作将自动利用移动语义。与默认的复制构造函数不同,编译器不提供默认的move构造函数。
std::move就是一个将左值转化为右值的函数,例如:
template<typename T> void swap(T& a, T& b) { T t(std::move(a)); // a为空,t占有a的初始数据 a = std::move(b); // b为空, a占有b的初始数据 b = std::move(t); // t为空,b占有a的初始数据 }
完美的转发减少了重载函数,避免了转发的问题。转发的问题出现在你写通用函数将引用作为参数,将这些参数由函数调用的时候。举个例子,如果通用函数将 type const T&作为参数,那么调用函数不能修改参数的值。如果通用函数将 type T&作为参数,那么当参数是右值的时候,函数不能调用。通常来说,为了解决上述的问题,你需要提供重载函数,既要有type const T&参数的函数,也要有type T&参数的函数。结果呢,重载函数的数量随着参数数量呈指数递增。而右值引用能够使你只用一个函数就能适用于任意数量的参数。
原文:https://www.cnblogs.com/honernan/p/12012259.html