c++11中std::move函數(shù)的使用
C++11在運(yùn)行期有所增強(qiáng),通過增加核心的右值引用機(jī)制來改善臨時(shí)對(duì)象導(dǎo)致的效率低下的問題。C++臨時(shí)對(duì)象引入了多余的構(gòu)造、析構(gòu)及其內(nèi)部資源的申請(qǐng)釋放函數(shù)調(diào)用,導(dǎo)致程序運(yùn)行時(shí)性能受損,這一點(diǎn)被廣為詬病。C++標(biāo)準(zhǔn)委員會(huì)在C++11中引入了右值引用這個(gè)核心語言機(jī)制,來提升運(yùn)行期性能
過std::move,可以避免不必要的拷貝操作。
std::move是為性能而生。
std::move是將對(duì)象的狀態(tài)或者所有權(quán)從一個(gè)對(duì)象轉(zhuǎn)移到另一個(gè)對(duì)象,只是轉(zhuǎn)移,沒有內(nèi)存的搬遷或者內(nèi)存拷貝。
變量表達(dá)式是一個(gè)左值,即使這個(gè)變量是一個(gè)右值引用類型,也是將其看成是左值的。
于是有:變量是一個(gè)左值,我們不能將一個(gè)右值引用直接綁定到一個(gè)變量上,即使這個(gè)變量是右值引用類型也不行。
但是。我們可以顯式的將一個(gè)左值轉(zhuǎn)換為對(duì)應(yīng)的右值引用類型。另外,可以通過move庫(kù)函數(shù)來獲得綁定到左值上的右值引用。此函數(shù)定義在utility中。
如:
int &&rr1 = 42; //正確,字面值常量是右值 int &&rr2 = rr1; //錯(cuò)誤,表達(dá)式rr1是左值 int &&rr3 = std::move(rr1); //正確
move告訴編譯器我們有一個(gè)左值,但我們希望像一個(gè)右值一樣處理它。注意:調(diào)用move意味著承諾:除了對(duì)rr1賦值和銷毀它以外,我們不再使用它。在調(diào)用move之后,我們不能對(duì)移后源對(duì)象的值做任何假設(shè)。
(我們可以銷毀一個(gè)移后源對(duì)象,也可以賦予它新值,但是不能使用一個(gè)移后源對(duì)象的值。)
我們對(duì)move不提供using聲明,我們直接調(diào)用std::move而不是move。原因是:如果在應(yīng)用程序中定義一個(gè)標(biāo)準(zhǔn)庫(kù)中已有的名字,則將出現(xiàn)一下兩種可能中的一種:
(1)要么根據(jù)一般的重載規(guī)則確定某次調(diào)用應(yīng)該執(zhí)行函數(shù)的哪個(gè)版本,
(2)要么應(yīng)用程序根本就不會(huì)執(zhí)行函數(shù)的標(biāo)準(zhǔn)庫(kù)版本。
因此,對(duì)于move的名字沖突相比其他標(biāo)準(zhǔn)庫(kù)函數(shù)的沖突頻繁的多。于是我們?cè)谡{(diào)用move函數(shù)時(shí),是使用std::move而不是move。
原型定義中的原理實(shí)現(xiàn):
首先,函數(shù)參數(shù)T&&是一個(gè)指向模板類型參數(shù)的右值引用,通過引用折疊,此參數(shù)可以與任何類型的實(shí)參匹配(可以傳遞左值或右值,這是std::move主要使用的兩種場(chǎng)景)。關(guān)于引用折疊如下:
公式一)X& &、X&& &、X& &&都折疊成X&,用于處理左值
? string s("hello"); std::move(s) => std::move(string& &&) => 折疊后 std::move(string& ) 此時(shí):T的類型為string& typename remove_reference<T>::type為string? 整個(gè)std::move被實(shí)例化如下 string&& move(string& t) //t為左值,移動(dòng)后不能在使用t { ? ? //通過static_cast將string&強(qiáng)制轉(zhuǎn)換為string&& ? ? return static_cast<string&&>(t);? } ?
公式二)X&& &&折疊成X&&,用于處理右值
std::move(string("hello")) => std::move(string&&) //此時(shí):T的類型為string? // ? ? remove_reference<T>::type為string? //整個(gè)std::move被實(shí)例如下 string&& move(string&& t) //t為右值 { ? ? return static_cast<string&&>(t); ?//返回一個(gè)右值引用 }
簡(jiǎn)單來說,右值經(jīng)過T&&傳遞類型保持不變還是右值,而左值經(jīng)過T&&變?yōu)槠胀ǖ淖笾狄?
②對(duì)于static_cast<>的使用注意:任何具有明確定義的類型轉(zhuǎn)換,只要不包含底層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); //錯(cuò)誤:static不能去掉const性質(zhì) static_cast<string>(cp); //正確?
③對(duì)于remove_reference是通過類模板的部分特例化進(jìn)行實(shí)現(xiàn)的,其實(shí)現(xiàn)代碼如下
//原始的,最通用的版本 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三個(gè)變量都是int類型 int i; remove_refrence<decltype(42)>::type a; ? ? ? ? ? ? //使用原版本, remove_refrence<decltype(i)>::type ?b; ? ? ? ? ? ? //左值引用特例版本 remove_refrence<decltype(std::move(i))>::type ?b; ?//右值引用特例版本?
總結(jié):
std::move實(shí)現(xiàn),首先,通過右值引用傳遞模板實(shí)現(xiàn),利用引用折疊原理將右值經(jīng)過T&&傳遞類型保持不變還是右值,而左值經(jīng)過T&&變?yōu)槠胀ǖ淖笾狄?,以保證模板可以傳遞任意實(shí)參,且保持類型不變。然后我們通過static_cast<>進(jìn)行強(qiáng)制類型轉(zhuǎn)換返回T&&右值引用,而static_cast<T>之所以能使用類型轉(zhuǎn)換,是通過remove_refrence<T>::type模板移除T&&,T&的引用,獲取具體類型T。
到此這篇關(guān)于c++11中std::move函數(shù)的使用的文章就介紹到這了,更多相關(guān)c++11 std::move函數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C/C++ assert()函數(shù)用法案例總結(jié)
這篇文章主要介紹了C/C++ assert()函數(shù)用法案例總結(jié),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-09-09深入解析C++的循環(huán)鏈表與雙向鏈表設(shè)計(jì)的API實(shí)現(xiàn)
這篇文章主要介紹了C++的循環(huán)鏈表與雙向鏈表設(shè)計(jì)的API實(shí)現(xiàn),文中的示例對(duì)于鏈表結(jié)點(diǎn)的操作起到了很好的說明作用,需要的朋友可以參考下2016-03-03C++與QML進(jìn)行數(shù)據(jù)交互的常見方法總結(jié)
這篇文章主要為大家詳細(xì)介紹了C++與QML進(jìn)行數(shù)據(jù)交互的常見方法,文中 的示例代碼講解詳細(xì),具有一定的參考價(jià)值,有需要的小伙伴可以跟隨小編一起了解一下2023-10-10深入理解C++中的new/delete和malloc/free動(dòng)態(tài)內(nèi)存管理及區(qū)別介紹
這篇文章主要介紹了深入理解C++中的new/delete和malloc/free動(dòng)態(tài)內(nèi)存管理,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09VC中CWinThread類以及和createthread API的區(qū)別分析
這篇文章主要介紹了VC中CWinThread類以及和createthread API的區(qū)別分析,較為詳細(xì)的講述了CWinThread類的原理,并以實(shí)例形式對(duì)AfxBeginThread函數(shù)的內(nèi)部實(shí)現(xiàn)進(jìn)行了解釋說明,需要的朋友可以參考下2014-10-10Matlab計(jì)算變異函數(shù)并繪制經(jīng)驗(yàn)半方差圖詳解
這篇文章主要為大家詳細(xì)介紹了基于MATLAB求取空間數(shù)據(jù)的變異函數(shù),并繪制經(jīng)驗(yàn)半方差圖的方法。文中的示例代碼講解詳細(xì),感興趣的可以了解一下2023-04-04C語言中設(shè)置進(jìn)程優(yōu)先順序的方法
這篇文章主要介紹了C語言中設(shè)置進(jìn)程優(yōu)先順序的方法,包括setpriority()函數(shù)和getpriority()函數(shù)以及nice()函數(shù),需要的朋友可以參考下2015-08-08VC實(shí)現(xiàn)ODBC數(shù)據(jù)庫(kù)操作實(shí)例解析
這篇文章主要介紹了VC實(shí)現(xiàn)ODBC數(shù)據(jù)庫(kù)操作的方法,非常有實(shí)用價(jià)值,需要的朋友可以參考下2014-07-07C語言判斷一個(gè)數(shù)是否是2的冪次方或4的冪次方
本文中我們來看一下如何用C語言判斷一個(gè)數(shù)是否是2的冪次方或4的冪次方的方法,并且判斷出來是多少次方,需要的朋友可以參考下2016-06-06C++任意線程通過hwnd實(shí)現(xiàn)將操作發(fā)送到UI線程執(zhí)行
做Windows界面開發(fā)時(shí),經(jīng)常需要在多線程環(huán)境中將操作拋到主線程執(zhí)行,下面我們就來學(xué)習(xí)一下如何在不需要重新定義消息以及接收消息的情況下實(shí)現(xiàn)這一要求,感興趣的可以了解下2024-03-03