作者:小 琛
欢迎转载,请标明出处
右值引用的概念
C++11提出了右值引用的概念,仍然是取别名,但只能对右值操作
int&& x =13;
double&& y=16.12;
右值与左值
左值与右值是C语言中的概念,但C标准并没有给出严格的区分方式,一般认为:可以放在=左边的,或者能够取地址的称为左值,只能放在=右边的,或者不能取地址的称为右值,但是也不一定完全正确,例如我们一般把将亡值也称为右值。
右值引用的两大用处
C++11之所以能提出右值引用,那必然是某些情况需要用到,常用到的情况有两种:移动语义(Move Semantics)、完美转发(Perfect forwarding)
移动语义(Move Semantics)
现有如下代码:
string operator+(const string& s)
{
char* ptemp=new char[strlen(_str)+strlen(s.str)+1];
strcpy(ptemp,_str);
strcpy(ptemp+strlen(_str),s._str);
string strRet(ptemp);
return strRet;
}
当我们需要实现operator+时,我们通常定义个临时变量,用该临时变量构建新的string,最后返回这个新构建的string。
当strRet返回的时候,必须创建一个临时对象,这个临时对象创建好后,strRet则被销毁,最后使用返回的临时变量构造新的对象,新的对象被成功构造后,临时对象则被销毁。
仔细观察会发现:strRet、临时对象、新的对象创建时,都有自己独立的空间,而空间中存放内容也都相同,相当于创建了三个内容完全相同的对象,对于空间是一种浪费,程序的效率也会降低,而且临时对象确实作用不是很大,那能否对该种情况进行优化呢?
C++11提出了移动语义概念,这个概念本质是:将一个对象中资源移动到另一个对象中的一种方式,可以有效缓解诸如此类的问题。
如果要实现移动语义,必须使用右值引用
string(string&& s)
: _str(s._str)
{
s._str = nullptr;
}
完美转发(Perfect forwarding)
完美转发是指在函数模板中,完全依照模板的参数的类型,将参数传递给函数模板中调用的另外一个函数
所谓完美:
函数模板在向其他函数传递自身形参时,如果相应实参是左值,它就应该被转发为左值;如果相应实参是右值,它就应该被转发为右值。这样做是为了保留在其他函数针对转发而来的参数的左右值属性进行不同处理(比如参数为左值时实施拷贝语义;参数为右值时实施移动语义)。
C++11 通过forward函数来实现完美转发
void Fun(int &x) //普通类型引用
{
cout << "lvalue ref" << endl;
}
void Fun(int &&x) //普通类型右值引用
{
cout << "rvalue ref" << endl;
}
void Fun(const int &x) //const类型普通引用
{
cout << "const lvalue ref" << endl;
}
void Fun(const int &&x) //const类型的右值引用
{
cout << "const rvalue ref" << endl;
}
//通过函数模板作为转发函数
template<typename T>
//完美转发:t是左值---->传给Fun函数,t应该也是左值
// t如果是右值--->传给Fun函数,t应该是右值
void PerfectForward(T &&t)
{
Fun(std::forward<T>(t)); //forward把t转化为右值。
//Fun(t);
}
int main()
{
PerfectForward(10); // 10为右值
int a;
PerfectForward(a); // lvalue ref
PerfectForward(std::move(a)); // rvalue ref
const int b = 8;
PerfectForward(b); // const lvalue ref
PerfectForward(std::move(b)); // const rvalue ref
return 0;
}