1.右值跟左值由什么區(qū)別
左值是指表達(dá)式結(jié)束后依然存在的持久對象,右值是指表達(dá)式結(jié)束時(shí)就不在存在的臨時(shí)對象。
2.什么是右值脸秽?
在C++11中骂删,右值由兩個(gè)概念構(gòu)成掌动,一個(gè)是將亡值四啰,另一個(gè)是純右值。
純右值:非引用返回的臨時(shí)變量粗恢、運(yùn)算表達(dá)式產(chǎn)生的臨時(shí)變量柑晒、原始字面量、lambda表達(dá)式等眷射。
將亡值:C++11新增的匙赞、與右值引用相關(guān)的表達(dá)式,比如凭迹,將要被移動的對象罚屋、T&&函數(shù)返回值、std::move返回值和轉(zhuǎn)換為T&&的類型的轉(zhuǎn)換函數(shù)的返回值嗅绸。
3.如何區(qū)分右值脾猛?
所有具名變量或?qū)ο蠖际亲笾担抑挡痪呙?br> 便捷方法:能不能對表達(dá)式取地址鱼鸠,如果能猛拴,則為左值,否則為右值蚀狰。
4.一些特性
無論聲明左值引用還是右值引用愉昆,都需要立即初始化,因?yàn)橐妙愋捅旧聿粨碛薪壎▽ο蟮膬?nèi)存麻蹋,只是該對象的別名跛溉。
常量左值引用也可以用來做性能優(yōu)化,因?yàn)槌A孔笾狄檬且粋€(gè)“萬能”的引用類型扮授,可以接收左值芳室、右值、常量左值和常量右值刹勃。需要注意的是非常量左值引用只能接收左值堪侯。
T&& 不一定就是表示右值,它綁定的類型是未定的荔仁,既可能是左值也有可能是右值伍宦。
template<typename T>
void f(T&& param);
f(10); //10是右值
int x = 10;
f(x); //x是左值
如上例,param有時(shí)是左值乏梁,有時(shí)是右值次洼,這表示param實(shí)際上是一個(gè)未定的引用類型(universal reference)。它必須被初始化遇骑,
如果&&被一個(gè)左值初始化就是左值滓玖;如果&&被一個(gè)右值初始化就是右值。
需要注意的是质蕉,只有當(dāng)發(fā)生自動類型推斷時(shí)势篡,比如函數(shù)模板的類型自動推導(dǎo)翩肌,或auto關(guān)鍵字,&&才是一個(gè)universal reference禁悠。
template<typename T>
void f(T&& param); //universal reference念祭,T的類型需要推導(dǎo)
class Test {
...
Test(Test&& rhs); //右值引用,已經(jīng)定義了一個(gè)特定的類型碍侦,沒有類型推斷
...
}
void f(std::vector<T>&& param) //右值引用粱坤,在調(diào)用 f 前,T的類型已經(jīng)確定了
void f(const T&& param) //右值引用瓷产,universal reference僅發(fā)生在T&&下站玄,任何一點(diǎn)的附加條件都會使之失效
5.引用折疊
由于存在T&&這種未定的引用類型,當(dāng)它作為參數(shù)時(shí)濒旦,有可能被一個(gè)左值引用或右值引用的參數(shù)初始化株旷,這種 經(jīng)過類型推導(dǎo)后的T&&類型,相比于右值引用(&&)會發(fā)生類型的變化尔邓,這種變化被稱為引用折疊晾剖。
引用折疊規(guī)則:
(1)所有的右值引用疊加到右值引用上仍然還是一個(gè)右值引用。
(2)所有的其他引用類型之間的疊加都將變成左值引用梯嗽。
左值和右值是獨(dú)立于它的類型的齿尽,右值引用有可能是左值也可能是右值,編譯器會將已命名的右值引用視為左值灯节,而將未命名的右值引用視為右值循头。
int&& var1 = 0; //var1的類型是int&&,但是本身是一個(gè)左值
auto&& var2 = var1; //根據(jù)引用折疊規(guī)則(2)炎疆,var2的類型是int&
下面在看一個(gè)例子:
int w1, w2;
auto&& v1 = w1; //v1是universal reference, 被左值初始化卡骂,所以最終是一個(gè)左值
decltype(w1)&& v2 = w2; //報(bào)錯(cuò)!v2是一個(gè)右值引用類型磷雇,無法被左值初始化
如何將一個(gè)左值賦給一個(gè)右值引用類型呢?使用std::move, 可以將一個(gè)左值轉(zhuǎn)換為右值躏救。