可以取地址的涩禀、有名字的就是左值曹货,反之咆繁,不能取地址的、沒有名字的就是右值控乾。
例如:a = b + c;
在這個加法賦值表達式中么介,&a是允許的操作,但&(b + c)這樣的操作則不會通過編譯蜕衡。因此a是一個左值壤短,(b + c)是一個右值。
在C++11中慨仿,右值引用就是對一個右值進行引用的類型久脯。事實上,由于右值通常不具有名字镰吆,我們也只能通過引用的方式找到它的存在帘撰。通常情況下,我們只能是從右值表達式獲得其引用万皿。比如:
T && a = ReturnRvalue();
右值引用和左值引用都是屬于引用類型摧找。無論是聲明一個左值引用還是右值引用核行,都必須立即進行初始化。而其原因可以理解為是引用類型本身自己并不擁有所綁定對象的內(nèi)存蹬耘,只是該對象的一個別名芝雪。左值引用是具名變量值的別名,而右值引用則是不具名(匿名)變量的別名综苔。
在上面的例子中惩系,ReturnRvalue函數(shù)返回的右值在表達式語句結(jié)束后,其生命也就終結(jié)了(通常我們也稱其具有表達式生命期)如筛,而通過右值引用的聲明堡牡,該右值又“重獲新生”,其生命期將與右值引用類型變量a的生命期一樣杨刨。只要a還“活著”晤柄,該右值臨時量將會一直“存活”下去。
所以相比于以下語句的聲明方式:
T b = ReturnRvalue();
我們剛才的右值引用變量聲明拭嫁,就會少一次對象的析構(gòu)及一次對象的構(gòu)造可免。因為a是右值引用,直接綁定了ReturnRvalue()返回的臨時量做粤,而b只是由臨時值構(gòu)造而成的浇借,而臨時量在表達式結(jié)束后會析構(gòu)因應(yīng)就會多一次析構(gòu)和構(gòu)造的開銷。
不過值得指出的是怕品,能夠聲明右值引用a的前提是ReturnRvalue返回的是一個右值妇垢。通常情況下,右值引用是不能夠綁定到任何的左值的肉康。比如下面的表達式就是無法通過編譯的闯估。
int c;
int && d = c;
相對地,在C++98標(biāo)準(zhǔn)中就已經(jīng)出現(xiàn)的左值引用是否可以綁定到右值(由右值進行初始化)呢吼和?比如:
T & e = ReturnRvalue();
const T & f = ReturnRvalue();
這樣的語句是否能夠通過編譯呢涨薪?這里的答案是:e的初始化會導(dǎo)致編譯時錯誤,而f則不會炫乓。
出現(xiàn)這樣的狀況的原因是刚夺,在常量左值引用在C++98標(biāo)準(zhǔn)中開始就是個“萬能”的引用類型。它可以接受非常量左值末捣、常量左值侠姑、右值對其進行初始化。而且在使用右值對其初始化的時候箩做,常量左值引用還可以像右值引用一樣將右值的生命期延長莽红。不過相比于右值引用所引用的右值,常量左值所引用的右值在它的“余生”中只能是只讀的邦邦。相對地安吁,非常量左值只能接受非常量左值對其進行初始化醉蚁。
使用左值引用,臨時對象被直接作為函數(shù)的參數(shù)柳畔,而不需要從中拷貝一次馍管,如果以右值引用為參數(shù)聲明如下函數(shù):
void AcceptRvalueRef(Copyable && ) {}
也同樣可以減少臨時變量拷貝的開銷郭赐。進一步地薪韩,還可以在AcceptRvalueRef中修改該臨時值(這個時候臨時值由于被右值引用參數(shù)所引用,已經(jīng)獲得了函數(shù)時間的生命期)捌锭。不過修改一個臨時值的意義通常不大俘陷,除非使用移動語義。
就本例而言观谦,如果我們這樣實現(xiàn)函數(shù):
void AcceptRvalueRef(Copyable && s) {
Copyable news = std::move(s);
}
這里std::move的作用是強制一個左值成為右值拉盾。該函數(shù)就是使用右值來初始化Copyable變量news。當(dāng)然豁状,如同我們在上小節(jié)提到的捉偏,使用移動語義的前提是Copyable還需要添加一個以右值引用為參數(shù)的移動構(gòu)造函數(shù),比如:
Copyable(Copyable &&o) { /* 實現(xiàn)移動語義 */ }
對于本例而言泻红,如果我們不聲明移動構(gòu)造函數(shù)夭禽,而只聲明一個常量左值的構(gòu)造函數(shù)會發(fā)生什么?如同剛才提到的谊路,常量左值引用是個“萬能”的引用類型讹躯,無論左值還是右值,常量還是非常量缠劝,一概能夠綁定潮梯。那么如果Copyable沒有移動構(gòu)造函數(shù),下列語句:
Copyable news = std::move(s);
將調(diào)用以常量左值引用為參數(shù)的拷貝構(gòu)造函數(shù)惨恭。這是一種非常安全的設(shè)計—移動不成秉馏,至少還可以執(zhí)行拷貝。因此脱羡,通常情況下萝究,程序員會為聲明了移動構(gòu)造函數(shù)的類再聲明一個常量左值為參數(shù)的拷貝構(gòu)造函數(shù),以保證在移動構(gòu)造不成時轻黑,可以使用拷貝構(gòu)造糊肤。
參考:http://book.2cto.com/201306/25366.html