我所知道的Move語義與完美轉發
一、臨時變量效率問題
///////////////////////////////////
std::vector<int> f()
{
std::vector<int> v;
// stuff
return v;
}
std::vector<int> arr(f());
//////////////////////////////////
這部分代碼做了三件事情:
1、 創建v
2、 用v構造f()的返回值
3、 用f()的返回值構造arr
問題:在此過程中總共構造了3個v的副本,若能將v直接構造在arr處,就可以避免2次
不必要的拷貝構造過程。怎麼辦呢?
在C++11之前,這種構造開銷通過RVO(返回值優化)來解決,但是對於如下代碼:
//////////////////////////////////
std::vector<int> arr;
arr = fun();
//////////////////////////////////
編譯器就無能爲力了。
直到C++11的到來,該問題才被完美解決。
二、右值引用
爲了解決臨時變量的效率問題,C++11引入了“右值引用”。在接下來的文章中,我
將逐步解釋“右值引用”如何成爲美貌與智慧並重、英雄與狹義的化身。
左值、右值是表達式的屬性,而非對象的屬性。左值在表達式結束之後任然存在,而
右值在表達式結束之後就會析構。
根據右值定義,第一節提到的f()就屬於右值。
爲了說明後續的問題,我將C++11標準的若干規則羅列如下:
假設有類型T,T&和const T&表達了傳統的左值引用,而T&&表達新引入的右值引用。
綁定規則:
1、const T &和T&&可以綁定到右值;
2、T&只能綁定左值;
3、右值優先綁定到T&&;
引用摺疊規則:
T & & ==> T &
T & && ==> T &
T && & ==> T &
T && && ==> T &&
是的,我目前只能告訴你這些規則,至於爲什麼C++標準這樣定義規則是合理的,我
還沒法做出有說服力的回答。
三、Move 語義
還記得std::vector的swap方法麼?
//////////////////////////////////
std::vector<int> tmp;
// tmp stuff
std::vector<int> arr;
arr.swap(tmp);
//////////////////////////////////
要是能確定tmp不再有用,那麼將tmp的內容swap過來是非常優雅和高效的手段。實際上,
Move semantic 正是這種思想。
問題是怎麼表明tmp不再有用?C++11標準庫提供了一個方法模板:
template<typename T>
std::remove_reference<T>::type && move(T &&);
對於move的實現放在後邊的章節解釋,目前只需要明白std::move<T>(x)調用返回對x的右值
引用。
假設有如下實現的類:
//////////////////////////////////
class M
{
public:
M(std::vector<int> && v) // move constructor
{
m_v = std::move(v);
}
M(const std::vector<int> & v)
{
m_v = v;
}
M& operator=(std::vector<int> && v) // move assignment
{
m_v.swap(v);
}
M& operator=(const std::vector<int> & v)
{
m_v.reserve(v.size());
std::copy(m_v.begin(), v.begin(), v.end());
}
std::vector<int> m_v;
//...
}
//////////////////////////////////
模板的第一個構造函數稱爲:move構造函數,形參爲右值引用。相對於第二個傳統的
拷貝構造函數,它的實現高效、優雅了太多。
考慮下面的調用
//////////////////////////////////
M m(f());
std::vector<int> tmp;
m = tmp;
m = std::move(tmp);
//////////////////////////////////
根據綁定規則,f()優先綁定到右值引用,因此m將通過move構造函數構造。然後,調用
普通賦值操作爲m賦值,之後又調用move賦值操作爲m賦值。
四、完美轉發
template<typename T>
class P
{
}
我所知道的Move語義與完美轉發
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.