C++11 移動(dòng)語義和右值引用


以下內(nèi)容引自[wikipedia](https://zh.wikipedia.org/wiki)

### 什么是右值?

在C++11提出右值引用之前寇壳,C++03及更早的C++標(biāo)準(zhǔn)中厅贪,表達(dá)式的“值分類”(value categories)屬性為左值或右值。

左值是對(duì)應(yīng)(refer to)內(nèi)存中有確定存儲(chǔ)地址的對(duì)象的表達(dá)式的值,而右值是所有不是左值的表達(dá)式的值。因而,右值可以是字面量辈赋、臨時(shí)對(duì)象等表達(dá)式。能否被賦值不是區(qū)分C++左值與右值的依據(jù)膏燕。

---

C++的const左值是不可賦值的钥屈;而作為臨時(shí)對(duì)象的右值可能允許被賦值。左值與右值的根本區(qū)別在于是否允許取地址&運(yùn)算符獲得對(duì)應(yīng)的內(nèi)存地址坝辫。

---

### 什么是右值引用?

作為一種追求執(zhí)行效率的語言篷就,C++在用臨時(shí)對(duì)象或函數(shù)返回值給左值對(duì)象賦值時(shí)的深度拷貝(deep copy)一直受到詬病〗Γ考慮到臨時(shí)對(duì)象的生命期僅在表達(dá)式中持續(xù)竭业,如果把臨時(shí)對(duì)象的內(nèi)容直接移動(dòng)(move)給被賦值的左值對(duì)象,效率改善將是顯著的及舍。這就是移動(dòng)語義的來源未辆。

與傳統(tǒng)的拷貝賦值運(yùn)算符(copy assignment)成員函數(shù)、拷貝構(gòu)造(copy ctor)成員函數(shù)對(duì)應(yīng)锯玛,移動(dòng)語義需要有移動(dòng)賦值(move assignment)成員函數(shù)鼎姐、移動(dòng)構(gòu)造(move ctor)成員函數(shù)的實(shí)現(xiàn)機(jī)制「瘢可以通過函數(shù)重載來確定是調(diào)用拷貝語義還是移動(dòng)語義的實(shí)現(xiàn)。

右值引用就是為了實(shí)現(xiàn)移動(dòng)語義與完美轉(zhuǎn)發(fā)所需要而設(shè)計(jì)出來的新的數(shù)據(jù)類型饭尝。右值引用的實(shí)例對(duì)應(yīng)于臨時(shí)對(duì)象肯腕;右值引用并區(qū)別于左值引用,用作形參時(shí)能重載辨識(shí)(overload resolution)是調(diào)用拷貝語義還是移動(dòng)語義的函數(shù)钥平。

### std::forward

std::forward用途是:如果函數(shù)forward的實(shí)參的數(shù)據(jù)類型是左值引用实撒,則返回類型為左值引用姊途;如果函數(shù)forward的實(shí)參的數(shù)據(jù)類型是右值引用,則返回類型為右值引用知态,返回值的分類屬于臨終值(臨終值對(duì)象既有存儲(chǔ)地址因此可以綁定到右值引用變量上捷兰,而且它又是一個(gè)即將停止使用的對(duì)象可以被移走內(nèi)容),從而把參數(shù)的信息完整地傳遞給下一級(jí)被調(diào)用的函數(shù)负敏。

從上述std::forward的定義實(shí)現(xiàn)來看贡茅,實(shí)參必須是個(gè)為左值的引用對(duì)象,但是實(shí)參的數(shù)據(jù)類型有兩種可能:

> + 實(shí)參的數(shù)據(jù)類型T是左值引用類型其做,std::forward的返回類型T&&根據(jù)引用塌縮規(guī)則變?yōu)門&顶考,即返回值仍為左值引用類型;

> + 實(shí)參的數(shù)據(jù)類型T是右值引用類型(這是因?yàn)橛抑狄妙愋偷木呙兞繉?shí)際上表現(xiàn)為左值)妖泄,std::forward的返回類型S&&根據(jù)引用塌縮規(guī)則變?yōu)镾&&驹沿,即返回值為右值引用類型。

### std::move

std::move是個(gè)模板函數(shù)蹈胡,把輸入的左值或右值轉(zhuǎn)換為右值引用類型的臨終值渊季。其核心是強(qiáng)制類型轉(zhuǎn)換static_cast()語句。

### 示例測試

代碼:

```

#include

#include

#include

#include

class Test{

private:

std::string _name;

public:

Test(const char* name):_name(name) {

std::cout << std::string("constructor ") + std::string(_name) << std::endl;

}

~Test() {

std::cout << std::string("destructor ") + std::string(_name) << std::endl;

}

std::string& print() {

return _name;

}

};

int main(int argc, const char** argv) {

std::cout << "teset begin" << std::endl;

std::cout<

auto testA = std::make_shared("test a");

auto testB = std::make_shared("test b");

auto testC = std::make_shared("test c");

{

std::vector> list;

list.push_back(testA);

// 無條件轉(zhuǎn)換成右值引用

list.push_back(std::move(testB));

// forward 有條件轉(zhuǎn)換

list.push_back(std::forward>(testC));

list.push_back(std::forward>(std::make_shared("test d")));

list.push_back(std::forward&&>(std::make_shared("test e")));

}

std::cout<

std::cout << "list life end" << std::endl;

std::cout << "teset end" << std::endl;

std::cout<

return 0;

}

```

運(yùn)行輸出:

```

g++ test.cpp

./a.out

teset begin

constructor test a

constructor test b

constructor test c

constructor test d

destructor test b

destructor test c

destructor test d

list life end

teset end

destructor test a

```

從結(jié)果可以看出, 使用std::move或std::forward后, 對(duì)象轉(zhuǎn)移到容器內(nèi)部, 容器銷毀時(shí)對(duì)象跟著銷毀, 此時(shí)shared_ptr對(duì)象失效, 成為無效對(duì)象(nullptr).

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末罚渐,一起剝皮案震驚了整個(gè)濱河市却汉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌搅轿,老刑警劉巖病涨,帶你破解...
    沈念sama閱讀 218,858評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異璧坟,居然都是意外死亡既穆,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門雀鹃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來幻工,“玉大人,你說我怎么就攤上這事黎茎∧衣” “怎么了?”我有些...
    開封第一講書人閱讀 165,282評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵傅瞻,是天一觀的道長踢代。 經(jīng)常有香客問我,道長嗅骄,這世上最難降的妖魔是什么胳挎? 我笑而不...
    開封第一講書人閱讀 58,842評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮溺森,結(jié)果婚禮上慕爬,老公的妹妹穿的比我還像新娘窑眯。我一直安慰自己,他們只是感情好医窿,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,857評(píng)論 6 392
  • 文/花漫 我一把揭開白布磅甩。 她就那樣靜靜地躺著,像睡著了一般姥卢。 火紅的嫁衣襯著肌膚如雪卷要。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評(píng)論 1 305
  • 那天隔显,我揣著相機(jī)與錄音却妨,去河邊找鬼。 笑死括眠,一個(gè)胖子當(dāng)著我的面吹牛彪标,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播掷豺,決...
    沈念sama閱讀 40,406評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼捞烟,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了当船?” 一聲冷哼從身側(cè)響起题画,我...
    開封第一講書人閱讀 39,311評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎德频,沒想到半個(gè)月后苍息,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡壹置,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年竞思,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片钞护。...
    茶點(diǎn)故事閱讀 40,090評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡盖喷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出难咕,到底是詐尸還是另有隱情课梳,我是刑警寧澤,帶...
    沈念sama閱讀 35,785評(píng)論 5 346
  • 正文 年R本政府宣布余佃,位于F島的核電站暮刃,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏爆土。R本人自食惡果不足惜椭懊,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,420評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望雾消。 院中可真熱鬧灾搏,春花似錦、人聲如沸立润。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽桑腮。三九已至泉哈,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間破讨,已是汗流浹背丛晦。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評(píng)論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留提陶,地道東北人烫沙。 一個(gè)月前我還...
    沈念sama閱讀 48,298評(píng)論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像隙笆,于是被迫代替她去往敵國和親锌蓄。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,033評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 接著上節(jié) mutex撑柔,本節(jié)主要介紹atomic的內(nèi)容瘸爽,練習(xí)代碼地址。本文參考http://www.cplusplu...
    jorion閱讀 73,664評(píng)論 1 14
  • 接著上節(jié) condition_varible 铅忿,本節(jié)主要介紹future的內(nèi)容剪决,練習(xí)代碼地址。本文參考http:/...
    jorion閱讀 14,795評(píng)論 1 5
  • C++右值引用 右值引用應(yīng)該是C++11引入的一個(gè)非常重要的技術(shù)檀训,因?yàn)樗且苿?dòng)語義(Move semantics)...
    小白將閱讀 2,187評(píng)論 2 13
  • 本文根據(jù)眾多互聯(lián)網(wǎng)博客內(nèi)容整理后形成柑潦,引用內(nèi)容的版權(quán)歸原始作者所有,僅限于學(xué)習(xí)研究使用肢扯,不得用于任何商業(yè)用途妒茬。 左...
    深紅的眼眸閱讀 11,279評(píng)論 1 12
  • 前言 把《C++ Primer》[https://book.douban.com/subject/25708312...
    尤汐Yogy閱讀 9,519評(píng)論 1 51