右值引用和std::move 以及std::forward(完美轉發)

左值與右值

左值是這樣一種表達式,它指向一塊物理內存,並允許我們通過運算符&來取得這塊內存的地址,而右值則是非左值的表達式。常量和匿名的臨時變量都爲右值,如函數返回值。

比如:int a=0; //a爲左值

          string s="ss";//s爲左值,"ss"爲右值

          string ss=string("e");//ss爲左值,string("e")爲右值

左值引用與右值引用

右值引用左值引用都是引用,都是一個變量(即都是一個左值),左值引用通過在類型名後加 & 來表示,而右值引用則通過在類型名後加 && 表示。只不過左值引用引用的是左值,而右值引用只能引用右值。函數形參都是左值,因爲函數形參都有名稱,都可以對形參進行取地址操作。

右值與右值引用

右值不是左值,右值引用是左值,是對右值的一種引用。c++11引入右值引用主要是爲了實現移動語義和完美轉發。右值引用本身沒什麼意義。

std::forward與std::move

std::forward實現

template<class TPYE>
TPYE&& forward(typename remove_reference<TPYE>::type& a) noexcept
{
  return static_cast<TPYE&&>(a);
}

先看remove_reference的實現,顧明思議就是去掉引用:

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;};

std::forward實現了完美轉發看下面的代碼(參考鏈接:https://blog.csdn.net/victorydh123/article/details/73603830):

void f(int&& a) {
    std::cout << "rvalue" << std::endl;
}

void f(int& a) {
    std::cout << "lvalue" << std::endl;
}

template<typename T>
void test(T&& a) {
    f(forward<T>(a));//如果沒有forward 將永遠調用左值版本,因爲右值引用是左值。右值引用的形參只能接受右值。完美轉發實現了傳遞進來什麼類型,我就返回什麼類型。其實就是解決了右值引用形參傳入後,形參本身已經是一個左值了,不能作爲下一個函數的右值引用參數。
}

template<typename T>
T&& forward(std::remove_reference_t<T>& arg)
{
    return static_cast<T&&>(arg);
}

int main()
{

    int a = 10;
    test(a);//"lvalue"
    test(std::move(a));//"rvalue"

    //system("pause"); //for windows VS to pause to see the output
    return 0;
}

模板推斷時,引用的摺疊規則:

& & -> & 
& && -> & 
&& & -> & 
&& && -> && 

當參數是一個左值時,在模板類型推斷的時候,左值會被推斷成左值引用,不管傳遞的參數是左值類型還是左值引用,通通變成左值引用。

std::move的實現代碼也很簡單

template<typename _Tp>  
inline typename std::remove_reference<_Tp>::type&&  move(_Tp&& __t)  
{ return static_cast<typename std::remove_reference<_Tp>::type&&>(__t); } 

就是將__t轉爲右值引用返回。

 

看上去move什麼也沒做,沒錯std::move並不產生新的對象,不會調用構造函數,只是做了一個類型轉換,這樣做的目的主要是爲了支持移動構造和移動賦值,因爲移動構造和移動賦值的參數類型爲右值引用。

要了解移動構造和移動賦值請百度“移動構造和移動賦值”或者參考這篇博客:https://www.cnblogs.com/ldlchina/p/6608154.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章