您的位置:首页 > 编程语言 > C语言/C++

[C/C++不常见语法特性]_[初级]_[左值-右值-lvalue-rvalue]

2016-02-18 14:45 471 查看
参考:
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



左值(lvalue)

lvalue: An lvalue (so called, historically, because lvalues could appear on the left-hand side of an assignment expression) designates a function or an object. [Example: If E is an expression of pointer type, then *E is an lvalue expression referring to the object or function to which E points. As another example, the result of calling a function whose return type is an lvalue reference is an lvalue. —end example ] -- 3.10 Lvalues and rvalues
左值: 一个左值( 之所以这么叫是因为历史原因: 因为这些左值出现在赋值表达式的左边) 指明了一个函数或者一个对象. [例子: 如果E是一个指针类型的表达式,那么*E 就是一个引用这个E指针指向的对象或函数的左值表达式. 另一个例子是, 请求一个函数的返回值是一个左值引用就是一个左值]

An lvalue refers to an object that persists beyond a single expression. You can think of an lvalue as an object that has a name. All variables, including nonmodifiable (const) variables -- Lvalues and Rvalues (Visual C++)
一个左值引用了一个对象,这个对象在单个表达式外依旧保持可用. 你可以认为一个左值是一个具有名字的对象. 所有变量, 包括不可以修改的(const)变量

An lvalue ("left value") expression is an expression that has identity and cannot 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. -- Value categories 一个左值表达式 是一种具有id(标识)的,不能被moved from的(即不能被直接move,必须先转换为右值).左值的命名是历史的原因,反映了左值表达式作为赋值操作符的左操作数来使用的.

右值(rvalue)

rvalue: An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment expression) is an xvalue, a temporary object (12.2) or subobject thereof, or a value that is not associated with an object. -- 3.10 Lvalues and rvalues
一个右值可以是一个xvalue,一个临时对象或者临时对象的子对象, 或者一个没关联到一个对象的值.

An rvalue is a temporary value that does not persist beyond the expression that uses it. -- Lvalues and Rvalues (Visual C++).
一个右值是一个临时值,它在表达式外(只有表达式使用这个右值)不再存储使用.

An rvalue ("right value") expression is an expression that is either a prvalue or an xvalue. It can be moved from. It may or may not have identity -- Value categories
一个右值表达式是一个prvalue或者一个xvalue, 它能被 moved from.

xvalue(到期值 expiring value)

An rvalue (so called, historically, because rvalues could appear on the right-hand side of an assignment expression) is an xvalue, a temporary object or subobject thereof, or a value that is not associated with an object. -- 3.10 Lvalues and rvalues

An xvalue ("expiring value") expression is an expression that has identity and can be moved from.
-- Value categories

glvalue(广义左值? "generalized" lvalue)

A glvalue (“generalized” lvalue) is an lvalue or an xvalue. -- 3.10 Lvalues and rvalues

A glvalue ("generalized lvalue") expression is an expression that is either an lvalue or an xvalue.It has identity. It may or may not be moved from. -- Value categories

A prvalue(纯右值)

(“pure” rvalue) is an rvalue that is not an xvalue. [Example: The result of calling a function whose return type is not a reference is a prvalue. The value of a literal such as 12, 7.3e5, or true is also a prvalue. -- 3.10 Lvalues and rvalues

A prvalue ("pure rvalue") expression is an expression that does not have identity and can be moved from. -- Value categories

摘录cppreference.com, 判断左右值的情景:

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 called lvalue expressions;
have identity and can be moved from are called xvalue expressions;
do not have identity and can be moved from are called prvalue expressions;
do not have identity and cannot be moved from are not used[1].
lvalue

An lvalue ("left value") expression is an expression that has identity and cannot 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 as std::cin or std::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 as std::getline(std::cin, str), std::cout << 1, str1 = str2, or ++it;
a = b, a += b, a %= b, and all other built-in assignment and compound assignment expressions;
++a and --a, the built-in pre-increment and pre-decrement expressions;
*p, the built-in indirection expression;
a[n] and p[n], the built-in subscript expressions, except where
a
is an array rvalue (since C++11);
a.m, the member of object expression, except where
m
is a member enumerator or a non-static member function, or where
a
is an rvalue and
m
is a non-static data member of non-reference type;
p->m, the built-in member of pointer expression, except where
m
is a member enumerator or a non-static member function;
a.*mp, the pointer to member of object expression, where
a
is an lvalue and
mp
is a pointer to data member;
p->*mp, the built-in pointer to member of pointer expression, where
mp
is a pointer to data member;
a, b, the built-in comma expression, where
b
is an lvalue;
a ? b : c, the ternary conditional expression for some
a
,
b
, and
c
;
a string literal, such as "Hello, world!";
a cast expression to lvalue reference type, such as static_cast<int&>(x);
a function call or an overloaded operator expression of rvalue reference to function return type;
a cast expression to rvalue reference to function type, such as static_cast<void (&&)(int)>(x).
(since C++11)
Properties:

Same as glvalue (below).
Address of an lvalue may be taken: &++i[2] and &std::endl are 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 to initialize an lvalue reference; this associates a new name with the object identified by the expression.
rvalue (until C++11)prvalue (since C++11)

A prvalue ("pure rvalue") expression is an expression that does not have identity and can be moved from.

The following expressions are prvalue expressions:

a literal (except for string literal), such as 42, true or nullptr;
a function call or an overloaded operator expression of non-reference return type, such as str.substr(1, 2), str1 + str2, or it++;
a++ and a--, the built-in post-increment and post-decrement expressions;
a + b, a % b, a & b, a << b, and all other built-in arithmetic expressions;
a && b, a || b, ~a, the built-in logical expressions;
a < b, a == b, a >= b, and all other built-in comparison expressions;
&a, the built-in address-of expression;
a.m, the member of object expression, where
m
is a member enumerator or a non-static member function[3], or where
a
is an rvalue and
m
is a non-static data member of non-reference type (until C++11);
p->m, the built-in member of pointer expression, where
m
is a member enumerator or a non-static member function[3];
a.*mp, the pointer to member of object expression, where
mp
is a pointer to member function[3], or where
a
is an rvalue and
mp
is a pointer to data member (until C++11);
p->*mp, the built-in pointer to member of pointer expression, where
mp
is a pointer to member function[3];
a, b, the built-in comma expression, where
b
is an rvalue;
a ? b : c, the ternary conditional expression for some
a
,
b
, and
c
;
a cast expression to non-reference type, such as static_cast<double>(x), std::string{}, or (int)42;
a lambda expression, such as [](int x){ return x * x; }.
(since C++11)
Properties:

Same as rvalue (below).
A prvalue cannot be polymorphic: the dynamic type of the object it identifies is always the type of the expression.
A non-class prvalue cannot be cv-qualified.
A prvalue cannot have incomplete type (except for type void, see below, or when used in decltype specifier).
xvalue

An xvalue ("expiring value") expression is an expression that has identity and can 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-in subscript expression, where
a
is an array rvalue;
a.m, the member of object expression, where
a
is an rvalue and
m
is a non-static data member of non-reference type;
a.*mp, the pointer to member of object expression, where
a
is an rvalue and
mp
is a pointer to data member;
a ? b : c, the ternary conditional expression for some
a
,
b
, and
c
;
a cast expression to rvalue reference to object type, such as static_cast<char&&>(x).
Properties:

Same as rvalue (below).
Same as glvalue (below).
Like prvalues, xvalues bind to rvalue references, but unlike prvalues, an xvalue may be polymorphic, and a non-class xvalue may be cv-qualified.

(since C++11)
Mixed categories

glvalue

A glvalue ("generalized lvalue") expression is an expression that is either an lvalue or an xvalue. It has 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 be polymorphic: the dynamic type of the object it identifies is not necessarily the static type of the expression.
A glvalue can have incomplete type, where permitted by the expression.
rvalue

An rvalue ("right value") expression is an expression that is either a prvalue or an xvalue. It can 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 to initialize 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 to initialize 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 when two overloads of 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 the move constructor, and likewise with copy and move assignment operators).
(since C++11)

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: