C++的lvalue, rvalue, rvalue reference 和Move Semantics

神秘的C++, 這就是C++的一個(gè)神秘之處。這是什么?? 我也是很抓狂。

Left Value: 左值:

something you can assign to.
在賦值操作的左邊;
可以是address (&foo).
如果它有一個(gè)名字,then it is left value.
refer to 一個(gè)內(nèi)存地址,允許我們用&取地址。

Right value:

Something you can't assign to.
如臨時(shí)變量;temporary object returned by value;
出現(xiàn)在賦值操作的右邊。
An rvalue is an expression that is not an lvalue.

int& foo();
int* r = &foo(); // 可以, 因?yàn)閒oo返回的是一個(gè)reference, 是一個(gè)左值, 可以取地址
int bar();
int* r = &bar(); //不可以,因?yàn)閎ar()返回的是一個(gè)rvalue,不能取地址。

rvalue reference:

X& is a lvalue reference.
X&& is a rvalue reference.
Rvalue reference就是對(duì)一個(gè)無名小卒的reference。

void foo(X& x);
void foo(X&& x);
X x;
X foobar();
foo(x); // 左值引用
foo(foobar()); // 右值引用 

這里foo函數(shù)被overload. 可以是X& x 的輸入,也可以是X&&的輸入。
雖然可以任意設(shè)計(jì)這些overload, 但這樣的overload應(yīng)該之發(fā)生在copy和assignment operator上。別的函數(shù)不要亂來。

所以這...有什么用呢,說了半天浪費(fèi)我時(shí)間嗎?

我們?yōu)槭裁葱枰烙抑狄媚兀?br> R value reference 可以用來實(shí)現(xiàn)move semantics和perfect forwarding
Perfect forwarding改日再說.
Move Semantics主要是用來解決copy constructor和assignment operator(=)虛耗的。
okay. 你說move semantics很Diao我不質(zhì)疑, 可是為什么要用R value reference?
因?yàn)閏ompiler很膽小,只敢欺負(fù)Rvalue reference這樣的無名小卒, 沒有r value reference compiler不敢用move semantics。

比如

MyClass x;
MyClass foo();
x = foo();

如果沒有move semantics, 則foo產(chǎn)生的Object會(huì)被Copy一下,再assign給x. 如果有了move semantics, 則foo() return的 那個(gè)object 可以直接丟給x, 把reference 本身copy一下就好了。 x 原來的那個(gè)就直接丟掉了。
這樣就要求 MyClass的operator= 需要能接受 rvalue reference(), 因?yàn)?x = foo()的右邊是個(gè)右值。
所以 MyClass 要有一個(gè)operator overload

MyClass& operator=(MyClass&& rhs) {
  // move semantics
  return *this;
} 

如果還有一個(gè) operator= overload

MyClass& operator=(MyClass& lhs) {
  // 這是一個(gè)左值引用
}

那對(duì)于兩個(gè)overloaded的operator=, 一個(gè)是左值引用的,一個(gè)是右值引用的, compiler怎么選呢?compiler怎么知道用哪一個(gè)?
if it has a name, then it is an lvalue. Otherwise, it is an rvalue。 通俗說就是無名小卒。
Move semantics只用來處理那些compiler確定是用完就扔的object, compiler謹(jǐn)小慎微怕出錯(cuò)。
只敢對(duì)付無名小卒,但凡有名有姓的,都怕程序員會(huì)惦記,不敢碰。

那如果非要用選用右值引用的怎么辦?如果我有兩個(gè)變量 a, b;

MyClass a, b;

如果我想把b轉(zhuǎn)移給a, 讓 a = b,
但是 這時(shí)compiler會(huì)自動(dòng)選左值引用的 operator=, 沒法實(shí)現(xiàn)move semantics.
這時(shí) 用a = std::move(b) , std::move(b)的返回值就是一個(gè)無名小卒。所以強(qiáng)制compiler用右值引用的。這程序員自已把b打成無名小卒,然后丟給compiler說你把它當(dāng)右值引用。當(dāng)然程序猿您以后可別惦記b。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容