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& move(T x) {
return static_cast&&>(x);
}

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++程序時,怎樣使用和管理第三方的開源庫?

TAG:編程語言 | C | CC | CPrimer |