參考:
1. http://en.cppreference.com/w/cpp/language/value_category
<< Value categories >>
2. https://msdn.microsoft.com/en-us/library/dd293668.aspx
<< Rvalue Reference Declarator: && >>
3. https://msdn.microsoft.com/en-us/library/f90831hc.aspx
<< Lvalues and Rvalues (Visual C++) >>
4. << Working Draft, Standard for Programming Language C ++ >> [Document Number: N3797]
3.10 Lvalues and rvalues
5. http://en.cppreference.com/w/cpp/utility/move
<< std::move >>
場景:
1. C++11 引入了std::move,它可以高效率的從一個左值資源移動到另一個左值資源裡,這個過程不需要再創建新的資源. 這對std::string,std::vector這種標准庫的資源操作更加精煉.使用標准庫時會大量使用這個std::move模板函數.
2. 在std::move的源碼裡又涉及到std::remove_reference 模板結構體,這個結構體又涉及到 "右值引用聲明(Rvalue Reference Declarator: &&)", 所以這裡還是講講基本的左值和右值.
左值和右值(Lvalues and rvalues)
1. 這裡的左值和右值可以稱為左值表達式和右值表達式,
因為每個C++表達式要麼是一個左值要麼是一個右值 -- Lvalues and Rvalues (Visual C++).
2. 左值和右值可以細分為以下類型: 圖
glvalue,rvalue,lvalue,xvalue,prvalue
一個左值表達式 是一種具有id(標識)的,不能被moved from的(即不能被直接move,必須先轉換為右值).左值的命名是歷史的原因,反映了左值表達式作為賦值操作符的左操作數來使用的.
一個右值表達式是一個prvalue或者一個xvalue, 它能被 moved from.
-- Value categories
The primary value categories correspond to two properties of expressions:
has identity: it's possible to determine whether the expression refers to the same entity as another expression, such as by comparing addresses of the objects or the functions they identify (obtained directly or indirectly); can be moved from:move constructor,move assignment operator, or another function overload that implements move semantics can bind to the expression.Expressions that:
have identity and cannot be moved from are calledlvalue expressions; have identity and can be moved from are calledxvalue expressions; do not have identity and can be moved from are calledprvalue expressions; do not have identity and cannot be moved from are not used[1].lvalue
Anlvalue("left value") expression is an expression thathas identityandcannot be moved from. The naming is historic and reflects the use of lvalue expressions as the left-hand operand of the assignment operator in the CPL programming language.
The following expressions are lvalue expressions:
the name of a variable or a function in scope, regardless of type, such asstd::cinorstd::endl. Even if the variable's type is rvalue reference, the expression consisting of its name is an lvalue expression; a function call or an overloaded operator expression of lvalue reference return type, such asstd::getline(std::cin, str),std::cout<<1,str1=str2, or++it; a=b,a+=b,a%=b, and all other built-inassignment and compound assignmentexpressions; ++aand--a, the built-inpre-increment and pre-decrementexpressions; *p, the built-inindirectionexpression; a[n]andp[n], the built-insubscriptexpressions, except wherea
is an array rvalue(since C++11); a.m, themember of objectexpression, except wherem
is a member enumerator or a non-static member function, or wherea
is an rvalue andm
is a non-static data member of non-reference type; p->m, the built-inmember of pointerexpression, except wherem
is a member enumerator or a non-static member function; a.*mp, thepointer to member of objectexpression, wherea
is an lvalue andmp
is a pointer to data member; p->*mp, the built-inpointer to member of pointerexpression, wheremp
is a pointer to data member; a, b, the built-incommaexpression, whereb
is an lvalue; a?b:c, theternary conditionalexpression for somea
,b
, andc
; astring literal, such as"Hello, world!"; a cast expression to lvalue reference type, such asstatic_castProperties:
Same as glvalue (below). Address of an lvalue may be taken:&++i[2]and&std::endlare valid expressions. A modifiable lvalue may be used as the left-hand operand of the built-in assignment and compound assignment operators. An lvalue may be used toinitialize an lvalue reference; this associates a new name with the object identified by the expression.rvalue(until C++11)prvalue(since C++11)
Aprvalue("pure rvalue") expression is an expression thatdoes not have identityandcan be moved from.
The following expressions are prvalue expressions:
aliteral(except forstring literal), such as42,trueornullptr; a function call or an overloaded operator expression of non-reference return type, such asstr.substr(1,2),str1+str2, orit++; a++anda--, the built-inpost-increment and post-decrementexpressions; a+b,a%b,a&b,a<arithmeticexpressions; a&&b,a||b,~a, the built-inlogicalexpressions; a=b, and all other built-incomparisonexpressions; &a, the built-inaddress-ofexpression; a.m, themember of objectexpression, wherem
is a member enumerator or a non-static member function[3], or wherea
is an rvalue andm
is a non-static data member of non-reference type(until C++11); p->m, the built-inmember of pointerexpression, wherem
is a member enumerator or a non-static member function[3]; a.*mp, thepointer to member of objectexpression, wheremp
is a pointer to member function[3], or wherea
is an rvalue andmp
is a pointer to data member(until C++11); p->*mp, the built-inpointer to member of pointerexpression, wheremp
is a pointer to member function[3]; a, b, the built-incommaexpression, whereb
is an rvalue; a?b:c, theternary conditionalexpression for somea
,b
, andc
; a cast expression to non-reference type, such asstatic_castProperties:
Same as rvalue (below). A prvalue cannot bepolymorphic: thedynamic typeof the object it identifies is always the type of the expression. A non-class prvalue cannot becv-qualified. A prvalue cannot haveincomplete type(except for type void, see below, or when used indecltype specifier).xvalue
Anxvalue("expiring value") expression is an expression thathas identityandcan be moved from.
The following expressions are xvalue expressions:
a function call or an overloaded operator expression of rvalue reference to object return type, such asstd::move(x); a[n], the built-insubscriptexpression, wherea
is an array rvalue; a.m, themember of objectexpression, wherea
is an rvalue andm
is a non-static data member of non-reference type; a.*mp, thepointer to member of objectexpression, wherea
is an rvalue andmp
is a pointer to data member; a?b:c, theternary conditionalexpression for somea
,b
, andc
; a cast expression to rvalue reference to object type, such asstatic_castProperties:
Same as rvalue (below). Same as glvalue (below).Like prvalues, xvalues bind to rvalue references, but unlike prvalues, an xvalue may bepolymorphic, and a non-class xvalue may becv-qualified.
Mixed categories
glvalue
Aglvalue("generalized lvalue") expression is an expression that is either an lvalue or an xvalue. Ithas identity. It may or may not be moved from.
Properties (note: these apply to pre-C++11 lvalues as well):
A glvalue may be implicitly converted to a prvalue with lvalue-to-rvalue, array-to-pointer, or function-to-pointerimplicit conversion. A glvalue may bepolymorphic: thedynamic typeof the object it identifies is not necessarily the static type of the expression. A glvalue can haveincomplete type, where permitted by the expression.rvalue
Anrvalue("right value") expression is an expression that is either a prvalue or an xvalue. Itcan be moved from. It may or may not have identity. The naming is historic and reflects the use of rvalue expressions as the right-hand operand of the assignment operator in the CPL programming language.
Properties (note: these apply to pre-C++11 rvalues as well):
Address of an rvalue may not be taken:&int(),&i++[4],&42, and&std::move(x)are invalid. An rvalue can't be used as the left-hand operand of the built-in assignment or compound assignment operators. An rvalue may be used toinitialize a const lvalue reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends. An rvalue may be used toinitialize an rvalue reference, in which case the lifetime of the object identified by the rvalue is extended until the scope of the reference ends. When used as a function argument and whentwo overloadsof the function are available, one taking rvalue reference parameter and the other taking lvalue reference to const parameter, an rvalue binds to the rvalue reference overload (thus, if both copy and move constructors are available, an rvalue argument invokes themove constructor, and likewise with copy and move assignment operators). (since C++11)