Fork me on GitHub

6/22/2011

[C++] 淺談左值與右值 - lvalue and rvalue

左值和右值感覺是基礎的東西,書本上經常會提到,但是始終不懂他們的用意是什麼,又有什麼區別,於是決心到網路上找看看有沒有精確又容易理解的說明!發現「Rvalue References: C++0x Features in VC10, Part 2」講解的還不錯,節錄如下:

lvalues and rvalues in C++98/03

C++03 3.10/1 says: "Every expression is either an lvalue or an rvalue."  It's important to remember that lvalueness versus rvalueness is a property of expressions, not of objects

原來 lvalue 和 rvalue 是用來描述 「expressions」 的屬性而非 objects!

Lvalues name objects that persist beyond a single expression.  For example, obj , *ptr , ptr[index] , and ++x are all lvalues.

Rvalues are temporaries that evaporate at the end of the full-expression in which they live ("at the semicolon").  For example, 1729 , x + y , std::string("meow") , and x++ are all rvalues.

左值讓一段 expression 成為一個有名稱的物件;而右值只是一段 expression 的結果且隨時會蒸發不見。為什麼 ++x 是左值而 x++ 卻是右值呢?

Both ++x and x++ increment x, but ++x returns the persistent object itself, while x++ returns a temporary copy. That's why ++x is an lvalue, while x++ is an rvalue

If you want to build up intuition for this, another way to determine whether an expression is an lvalue is to ask "can I take its address?". If you can, it's an lvalue. If you can't, it's an rvalue. For example, &obj , &*ptr , &ptr[index] , and &++x are all valid (even though some of those expressions are silly), while &1729 , &(x + y) , &std::string("meow") , and &x++ are all invalid.

並且可以利用一個簡單的方法來 check 一段 expression 是 lvalue 或 rvalue,就是看看可不可以使用 & 運算元對該 expression 取得他的位置

"A function call is an lvalue if and only if the result type is a reference." (C++03 5.2.2/10) Therefore, given vector v(10, 1729); , v[0] is an lvalue because operator[]() returns int& (and &v[0] is valid and useful), while given string s("foo"); and string t("bar"); , s + t is an rvalue because operator+() returns string (and &(s + t) is invalid)

Both lvalues and rvalues can be either modifiable (non-const) or non-modifiable (const). Here are examples:

左值和右值皆可以為 non-const 和 const (用 non-const 似乎較 modifiable 來的直覺),以下為範例:

string one("cute");
const string two("fluffy");
string three() { return "kittens"; }
const string four() { return "are an essential part of a healthy diet"; }

one; // modifiable lvalue
two; // const lvalue
three(); // modifiable rvalue
four(); // const rvalue

Type& binds to modifiable lvalues (and can be used to observe and mutate them). It can't bind to const lvalues, as that would violate const correctness. It can't bind to modifiable rvalues, as that would be extremely dangerous. Accidentally modifying temporaries, only to have the temporaries evaporate along with your modifications, would lead to subtle and obnoxious bugs, so C++ rightly prohibits this. And it can't bind to const rvalues, as that would be doubly bad. (Careful readers should note that I'm not talking about template argument deduction here.)

non-const reference 可以綁定 non-const lvalues,不可以綁定 const lvalues。這很容易理解,因為 reference 就只是一個 alias。

non-const reference 也不能綁定 non-const rvalue。因為 rvalue 只是一個暫態,沒有一個東西可以 hold 住他,所以你可能以為 non-const reference 可以對他做操控,但實際上卻不行。


const Type& binds to everything: modifiable lvalues, const lvalues, modifiable rvalues, and const rvalues (and can be used to observe them).

const reference 則可以綁定所有 (non-const lvalues, const lvalues, non-const rvalues 和 const rvalues)


接著還可以進一步牽扯到 C++0x 的新語言特性,有點複雜,因此有興趣的話可以再回原文參閱...


參考資料:
Rvalue References: C++0x Features in VC10, Part 2
http://blogs.msdn.com/b/vcblog/archive/2009/02/03/rvalue-references-c-0x-features-in-vc10-part-2.aspx

C++ Primer 中文版 p.60

... ...

No comments:

Post a Comment