右值

先来几个快速问答:
右值什么时候出现的?右值早就有了,右值引用直到c++11才有的
右值引用有什么用?为了减少拷贝。
为什么右值引用能减少拷贝?右值赋值给右值引用变量的时候,直接将右值对应的地址交给右值引用变量,相当于对应的内存换了个马甲。
什么时候用右值引用?一般都是将左值转换成右值,然后赋值给右值引用,来减少拷贝。

为了区分左右值,看几个例子,来自CSDN:

int a = 10;
int b = 20;
int *pFlag = &a;
vector<int> vctTemp;
vctTemp.push_back(1);
string str1 = "hello ";
string str2 = "world";
const int &m = 1;

请问,a,b, a+b, a++, ++a, pFlag, *pFlag, vctTemp[0], 100, string("hello"), str1, str1+str2, m分别是左值还是右值?
a和b都是持久对象(可以对其取地址),是左值;
a+b是临时对象(不可以对其取地址),是右值;
a++是先取出持久对象a的一份拷贝,再使持久对象a的值加1,最后返回那份拷贝,而那份拷贝是临时对象(不可以对其取地址),故其是右值;
++a则是使持久对象a的值加1,并返回那个持久对象a本身(可以对其取地址),故其是左值;
pFlag和*pFlag都是持久对象(可以对其取地址),是左值;
vctTemp[0]调用了重载的[]操作符,而[]操作符返回的是一个int &,为持久对象(可以对其取地址),是左值;
100和string("hello")是临时对象(不可以对其取地址),是右值;
str1是持久对象(可以对其取地址),是左值;
str1+str2是调用了+操作符,而+操作符返回的是一个string(不可以对其取地址),故其为右值;
m是一个常量引用,引用到一个右值,但引用本身是一个持久对象(可以对其取地址),为左值。

右值引用变量使用&&声明
int&& x = 3;
这里的3不是常量值,应该看成是临时值。

非常量左值引用只能获取非常量左值,如果获取一个非常量右值,可能这个右值已经被窃取了,不行;并且常量不能赋值给非常量引用,不管左右值都不行。
常量左值引用可以获取任意的值。
非常量右值引用只能获取非常量右值,如果获取一个常量右值,这个右值将会被窃取,不行;并且常量不能赋值给非常量引用,不管左右值都不行。
常量右值引用只能获取常量右值或非常量右值,如果获取一个左值,这个左值将将会被窃取,不行。

在类的构造函数中
常量值只能绑定到常量引用上,不能绑定到非常量引用上。
非常量值优先绑定到非常量引用上。
左值优先绑定到左值引用上,右值优先绑定到右值引用上。

右值引用变量本身是左值,怎样将他赋值给右值引用呢?使用move函数转化成右值。不再使用的左值也可以用move函数转化成右值。
int a = 1;
int&& x = std::move(a);
这里的a是左值,被转换成右值赋值给右值引用
函数里右值被赋值到一个右值引用变量,这个变量是左值,如果在使用这个变量就成左值了,如果还是希望保持参数的类型,就需要使用完美转发std::forward()

下面是一个万能函数包装器
template<class Function, class... Args>
inline auto FuncWrapper(Function && f, Args && ... args) -> decltype(f(std::forward<Args>(args)...))
{
//typedef decltype(f(std::forward<Args>(args)...)) ReturnType;
return f(std::forward<Args>(args)...);
//your code; you can use the above typedef.
}

猜你喜欢

转载自www.cnblogs.com/litandy2016/p/12297585.html