(X()) 將把右值 X() 轉換為X類型的無名右值引用。由9和16可知源碼中std::move函數的具體實現符合標准,
因為無論用左值a還是右值X()做參數來調用std::move函數,
該實現都將返回無名的右值引用(右值的一種),符合標准中該函數的定義。
不光是臨時變量,只要是你認為不再需要的數據,都可以考慮用std::move移動。
比較有名的std::move用法是在swap中:
1 template
2 void swap(T& a, T& b)
3 {
4 T t(std::move(a)); // a為空,t占有a的初始數據
5 a = std::move(b); // b為空, a占有b的初始數據
6 b = std::move(t); // t為空,b占有a的初始數據
7 }
總之,std::move是為性能而生的,正式因為了有了這個主動報告廢棄物的設施,所以C++11中的STL性能大幅提升,即使C++用戶仍然按找舊有的方式來編碼,仍然能因中新版STL等標准庫的強化中收益。
std::forward
函數功能
std::forward(u) 有兩個參數:T 與 u。當T為左值引用類型時,u將被轉換為T類型的左值,否則u將被轉換為T類型右值。如此定義std::forward是為了在使用右值引用參數的函數模板中解決參數的完美轉發問題。
源碼與測試代碼
[cpp] view
plaincopy
-
/// forward (as per N3143)
-
template
-
inline _Tp&&
-
forward(typename std::remove_reference<_Tp>::type& __t)
-
{ return static_cast<_Tp&&>(__t); }
-
-
template
-
inline _Tp&&
-
forward(typename std::remove_reference<_Tp>::type&& __t)
-
{
-
static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument"
-
" substituting _Tp is an lvalue reference type");
-
return static_cast<_Tp&&>(__t);
-
}
[cpp] view
plaincopy
-
#include
-
using namespace std;
-
-
struct X {};
-
void inner(const X&) {cout << "inner(const X&)" << endl;}
-
void inner(X&&) {cout << "inner(X&&)" << endl;}
-
template
-
void outer(T&& t) {inner(forward(t));}
-
-
int main()
-
{
-
X a;
-
outer(a);
-
outer(X());
-
inner(forward(X()));
-
}
-
//inner(const X&)
-
//inner(X&&)
-
//inner(X&&)
代碼說明
測試代碼第13行用X類型的左值 a 來測試forward函數,程序輸出表明 outer(a) 調用的是 inner(const X&) 版本,從而證明函數模板outer調用forward函數在將參數左值 a 轉發給了inner函數時,成功地保留了參數 a 的左值屬性。測試代碼第14行用X類型的右值 X() 來測試forward函數,程序輸出表明 outer(X()) 調用的是 inner(X&&) 版本,從而證明函數模板outer調用forward函數在將參數右值 X() 轉發給了inner函數時,成功地保留了參數 X() 的右值屬性。首先我們來分析 outer(a) 這種調用forward函數轉發左值參數的情況。模擬單步調用來到測試代碼第8行,T&& <=> X&, t <=> a 。
根據函數模板參數推導規則,T&& <=> X& 可推出 T <=> X& 。
forward(t) <=> forward(t),其中 t 為指向 a 的左值引用。
再次單步調用進入forward函數實體所在的源碼第4行或第9行。
先嘗試匹配源碼第4行的forward函數,_Tp <=> X& 。typename std::remove_reference<_Tp>::type <=> X 。
typename std::remove_reference<_Tp>::type& <=> X& 。形參 __t 與實參 t 類型相同,因此函數匹配成功。再嘗試匹配源碼第9行的forward函數,_Tp <=> X& 。typename std::remove_reference<_Tp>::type <=> X 。
typename std::remove_reference<_Tp>::type&& <=> X&& 。形參 __t 與實參 t 類型不同,因此函數匹配失敗。由10與13可知7單步調用實際進入的是源碼第4行的forward函數。static_cast<_Tp&&>(__t) <=> static_cast(t) <=> a。inner(forward(t)) <=> inner(static_cast(t)) <=> inner(a) 。outer(a) <=> inner(forward(t)) <=> inner(a)
再次單步調用將進入測試代碼第5行的inner(const X&) 版本,左值參數轉發成功。然後我們來分析 outer(X()) 這種調用forward函數轉發右值參數的情況。模擬單步調用來到測試代碼第8行,T&& <=> X&&, t <=> X() 。根據函數模板參數推導規則,T&& <=> X&& 可推出 T <=> X 。
forward(t) <=> forward(t),其中 t 為指向 X() 的右值引用。
再次單步調用進入forward函數實體所在的源碼第4行或第9行。先嘗試匹配源碼第4行的forward函數,_Tp <=> X 。typename std::remove_reference<_Tp>::type <=> X 。
typename std::remove_reference<_Tp>::type& <=> X& 。形參 __t 與實參 t 類型相同,因此函數匹配成功。再嘗試匹配源碼第9行的forward函數,_Tp <=> X 。typename std::remove_reference<_Tp>::type <=> X 。
typename std::remove_reference<_Tp>::type&& <=> X&& 。形參 __t 與實參 t 類型不同,因此函數匹配失敗。由25與28可知22單步調用實際進入的仍然是源碼第4行的forward函數。
static_cast<_Tp&&>(__t) <=> static_cast(t) <=> X()。inner(forward(t)) <=> inner(static_cast(t)) <=> inner(X())。outer(X()) <=> inner(forward(t)) <=> inner(X())
再次單步調用將進入測試代碼第6行的inner(X&&) 版本,右值參數轉發成功。
由17和32可知源碼中std::forward函數的具體實現符合標准,
因為無論用左值a還是右值X()做參數來調用帶有右值引用參數的函數模板outer,
只要在outer函數內使用std::forward函數轉發參數,
就能保留參數的左右值屬性,從而實現了函數模板參數的完美轉發。