目錄
(1)爲何要區分?
引用的類型是左值/右值,指明瞭其綁定的對象的狀態是仍有可能被使用,or不再被修改、使用甚至被銷燬。而對象的狀態(左值/右值)又可決定,如何“拷貝”對象所擁有的動態資源——拷貝or接管。這一操作依賴類內的拷貝/移動構造函數以及拷貝/移動賦值運算符。
下面以vector<int>舉例,窺探對象的狀態(左值/右值)對“拷貝”對象這一操作的影響:
#define HUGENUM 1000000000 //10億
int main()
{
vector<int> A(HUGENUM, 50), B, C; //vector類的對象內擁有動態資源
clock_t start, end;
start = clock();
B = A; // 拷貝資源
end = clock();
cout << "time consumed on copy is " << (end - start) / CLK_TCK << endl;
start = clock();
C = std::move(A); // 移動(接管)資源
end = clock();
cout << "time consumed on move is " << (end - start) / CLK_TCK << endl;
}
運行結果如下:
可見,對於擁有動態資源的對象,其狀態(左值/右值)決定了其被“拷貝”時的具體實現,而當對象擁有大量的動態資源時,這一實現會影響到運行效率。
(2)那什麼是左值/右值引用?
形式上,定義引用時有一個&修飾符的則爲左值引用,有兩個&修飾符的則爲右值引用。左值/右值引用必須綁定對應狀態的對象,如下:
---- 右值引用只能綁定到右值對象上;
---- 非const左值引用只能綁定到左值對象上,而const左值引用對於左值/右值對象均能綁定。(const左值引用無法修改其綁定的對象,這符合右值的設計理念)
(3)左值?右值?
左值可位於賦值號的左側和右側,其值既能被使用也能被修改。而右值只能位於賦值號右側,可使用而不可修改其值。
常見左值包括:定義的對象、引用(不論左值/右值)、賦值/下標/解引用/前置自增自減等運算符返回的值,以及返回類型爲引用類型的函數所返回的值;
常見右值包括:字面值常量、算數/關係/邏輯/位等運算返回的值、後置自增自減運算符返回的值,以及返回類型爲非引用類型的函數所返回的值。
(4)左值/右值,與左值/右值引用有什麼區別?
---- 左值/右值引用本身屬於左值,既能使用也能修改其綁定的對象的值。但我們在使用右值引用時,還是應該遵循右值的設計理念,即假設右值引用綁定的對象不會再被修改、使用,甚至可能立刻被銷燬;
---- 右值引用綁定的既可能是真實的右值如(3)所述,也可能是我們希望是右值但實際並不是的普通對象(利用std::move()轉換)。