int foo(const int& param)
{
printf("%d", param);
return 0;
}
由于const int& 既可以是左值也可以是右值,传入0或者int变量都能够满足。(但是似乎既然有左值引用的int&类型,就应该有对应的传入右值引用的类型int&& )。另外,这里返回的右值0,似乎不通过拷贝就无法赋值给左值res 。
于是有了移动语义,把临时对象的内容直接移动给被赋值的左值对象(std::move)。和右值引用,X&&是到数据类型X的右值引用。
int result = 0;
int&& foo(int&& param)
{
printf("%d", param);
return std::move(result);
}
int&& res = foo(0);
int *pres = &res;
将foo改为右值引用参数和返回值,返回右值引用,免去拷贝。这里res是具名引用,运算符右侧的右值引用作为左值,可以取地址。右值引用既有左值性质,也有右值性质。
上述例子还只存在于拷贝的性能问题。回到MemNew这样的函数模板。
template<class T>
T* Test(T arg)
{
return new T(arg);
}
template<class T>
T* Test(T& arg)
{
return new T(arg);
}
template<class T>
T* Test(const T& arg)
{
return new T(arg);
}
template<class T>
T* Test(T&& arg)
{
return new T(std::forward<T>(arg));
}
上述的前三种方式传参,第一种首先有拷贝消耗,其次有的参数就是需要修改的左值。第二种方式则无法传常数等右值。第三种方式虽然左值右值都能传,却无法对传入的参数进行修改。第四种方式使用右值引用,可以解决参数完美转发的问题。
std::forward能够根据实参的数据类型,返回相应类型的左值和右值引用,将参数完整不动的传递下去。
解释这个原理涉及到引用塌缩规则
T& & ->T&
T& &&->T&
T&& &->T&
T&& &&->T&&
template< class T > struct remove_reference {typedef T type;};
template< class T > struct remove_reference<T&> {typedef T type;};
template< class T > struct remove_reference<T&&> {typedef T type;};
template< class T > T&& forward( typename std::remove_reference<T>::type& t )
{
return static_cast<T&&>(t);
}
template<class T>
typename std::remove_reference<T>::type&& move(T&& a) noexcept
{
return static_cast<typename std::remove_reference<T>::type&&>(a);
}










