C++ primer第五版的一處不理解?
在括弧內的內容我有些不理解,為什麼sale實際上是一個左值?如果是左值不應該調用的是拷貝版本的函數么?萬分感謝。p562
參數裡面的右值,因為在函數體內部可以被重複引用,所以變成了左值。所以實際上只有調用函數的人認為傳進去的參數是右值,而函數體內部還是必須當左值來看待的。
這個規則只針對參數成立,因為這是沒有辦法的。實際上你給一個變數定義為右值類型是說不過去的(雖然語法上可以,就像函數返回const T一樣)。
能取地址的是左值,所有parameter可以取地址,所有parameter是左值。變數名是符號,符號對應的object都在棧上,std::move就是說,該變數名放棄它的object,所以現在object變成xvalue,可以被右值引用捕獲。只有literal沒有地址,是pure rvalue。其他的通過std::move搞出來的東西都是xvalue,就是說原來的變數名不要這個object了,原則上來說對應的object應該被析構,所以叫xvalue(eXpiring value),反正都要死的東西,所以拿去綁到右值引用上廢物利用了。
事實上來說。。。上邊都是語義上的要求,運行時什麼都沒有。看std::move的實現可以知道
template&
remove_reference_t&
return static_cast&
}
std::move不過是把變數類型轉換了一下,xvalue有地址,但是編譯器不讓你取,連literal這種pure rvalue也有地址(在data段上),就是編譯器不讓你取。
int main() {
cout &<&< "shut up and give me the address" &<&< endl;
}
如果比較熟悉程序的內存分布的筒子可以看出,上面程序的輸出就是在data段中literal的地址。
所以C++作為native language,永遠是一門運行時裸奔的語言,所有的類型都是編譯器的謊言。有名字的變數,都不是右值(這就是那前半句話『但是』的意義)!!不用管他的類型
的作用在於輔助函數重載決議,本身沒有任何附加意義。所以它只會在函數傳參的時候起效果。
-----------------------------------
再廢話一句吧,可以取地址的變數一定不是右值。這句話在C++11同樣適用。這個例子裡面,實參是右值,形參一定是左值,函數調用時實參move給形參。形參在棧上有空間,而且函數執行完畢後會析構的。
找原版看看,感覺翻譯的邏輯混亂
儘管sale的類型是右值引用類型
背景介紹,應該沒問題吧
但sale本身(和任何其他變數一樣)是個左值
任何變數都是左值--&>因為變數會存活一定的時間,不會立刻「死亡」
因此,我們到用一個move把一個右值引用綁定到sale上
首先,move函數會返回一個右值引用。
其次,int *p = i; 就好像這個初始化一樣,p的類型(指向int的指針)決定了我們可以用什麼來初始化p。PS:儘管有時候這麼寫:int *p; 有時候又這麼寫:int* p;
但是本質上:int* 是類型,p是名字。你可以翻到前面講右值引用的一章重新看一遍。
Type rref = literal // rref是右值引用
Type lref = rref // error : rref 是左值
即是說右值引用本身是一個左值。 再看你給出的圖片, 函數的參數sale是一個右值引用,本身是一個左值。要想調用sale的clone函數的右值版本就必須用std::move轉換為一個右值。
推薦閱讀:
※C++的RAND函數生成的值為什麼存在嚴重的不隨機性?
※extern C裡面能有C++代碼嗎?
※學習完 C++ Primer 能做什麼項目練手或者看什麼好的開源項目源碼?
※有哪些能炫技的代碼寫法?
※在Visual Studio開發c++程序時,怎樣使用和管理第三方的開源庫?