c++11中std::move函數的使用
C++11在運行期有所增強,通過增加核心的右值引用機制來改善臨時對象導致的效率低下的問題。C++臨時對象引入瞭多餘的構造、析構及其內部資源的申請釋放函數調用,導致程序運行時性能受損,這一點被廣為詬病。C++標準委員會在C++11中引入瞭右值引用這個核心語言機制,來提升運行期性能
過std::move,可以避免不必要的拷貝操作。
std::move是為性能而生。
std::move是將對象的狀態或者所有權從一個對象轉移到另一個對象,隻是轉移,沒有內存的搬遷或者內存拷貝。
變量表達式是一個左值,即使這個變量是一個右值引用類型,也是將其看成是左值的。
於是有:變量是一個左值,我們不能將一個右值引用直接綁定到一個變量上,即使這個變量是右值引用類型也不行。
但是。我們可以顯式的將一個左值轉換為對應的右值引用類型。另外,可以通過move庫函數來獲得綁定到左值上的右值引用。此函數定義在utility中。
如:
int &&rr1 = 42; //正確,字面值常量是右值 int &&rr2 = rr1; //錯誤,表達式rr1是左值 int &&rr3 = std::move(rr1); //正確
move告訴編譯器我們有一個左值,但我們希望像一個右值一樣處理它。註意:調用move意味著承諾:除瞭對rr1賦值和銷毀它以外,我們不再使用它。在調用move之後,我們不能對移後源對象的值做任何假設。
(我們可以銷毀一個移後源對象,也可以賦予它新值,但是不能使用一個移後源對象的值。)
我們對move不提供using聲明,我們直接調用std::move而不是move。原因是:如果在應用程序中定義一個標準庫中已有的名字,則將出現一下兩種可能中的一種:
(1)要麼根據一般的重載規則確定某次調用應該執行函數的哪個版本,
(2)要麼應用程序根本就不會執行函數的標準庫版本。
因此,對於move的名字沖突相比其他標準庫函數的沖突頻繁的多。於是我們在調用move函數時,是使用std::move而不是move。
原型定義中的原理實現:
首先,函數參數T&&是一個指向模板類型參數的右值引用,通過引用折疊,此參數可以與任何類型的實參匹配(可以傳遞左值或右值,這是std::move主要使用的兩種場景)。關於引用折疊如下:
公式一)X& &、X&& &、X& &&都折疊成X&,用於處理左值
string s("hello"); std::move(s) => std::move(string& &&) => 折疊後 std::move(string& ) 此時:T的類型為string& typename remove_reference<T>::type為string 整個std::move被實例化如下 string&& move(string& t) //t為左值,移動後不能在使用t { //通過static_cast將string&強制轉換為string&& return static_cast<string&&>(t); }
公式二)X&& &&折疊成X&&,用於處理右值
std::move(string("hello")) => std::move(string&&) //此時:T的類型為string // remove_reference<T>::type為string //整個std::move被實例如下 string&& move(string&& t) //t為右值 { return static_cast<string&&>(t); //返回一個右值引用 }
簡單來說,右值經過T&&傳遞類型保持不變還是右值,而左值經過T&&變為普通的左值引用.
②對於static_cast<>的使用註意:任何具有明確定義的類型轉換,隻要不包含底層const,都可以使用static_cast。
double d = 1; void* p = &d; double *dp = static_cast<double*> p; //正確 const char *cp = "hello"; char *q = static_cast<char*>(cp); //錯誤:static不能去掉const性質 static_cast<string>(cp); //正確
③對於remove_reference是通過類模板的部分特例化進行實現的,其實現代碼如下
//原始的,最通用的版本 template <typename T> struct remove_reference{ typedef T type; //定義T的類型別名為type }; //部分版本特例化,將用於左值引用和右值引用 template <class T> struct remove_reference<T&> //左值引用 { typedef T type; } template <class T> struct remove_reference<T&&> //右值引用 { typedef T type; } //舉例如下,下列定義的a、b、c三個變量都是int類型 int i; remove_refrence<decltype(42)>::type a; //使用原版本, remove_refrence<decltype(i)>::type b; //左值引用特例版本 remove_refrence<decltype(std::move(i))>::type b; //右值引用特例版本
總結:
std::move實現,首先,通過右值引用傳遞模板實現,利用引用折疊原理將右值經過T&&傳遞類型保持不變還是右值,而左值經過T&&變為普通的左值引用,以保證模板可以傳遞任意實參,且保持類型不變。然後我們通過static_cast<>進行強制類型轉換返回T&&右值引用,而static_cast<T>之所以能使用類型轉換,是通過remove_refrence<T>::type模板移除T&&,T&的引用,獲取具體類型T。
到此這篇關於c++11中std::move函數的使用的文章就介紹到這瞭,更多相關c++11 std::move函數內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- 詳解C++右值引用
- 一文搞懂c++中的std::move函數
- 解析C++11的std::ref、std::cref源碼
- C++右值引用與移動構造函數基礎與應用詳解
- c++元編程模板函數重載匹配規則示例詳解