General


每一个C++表达式(一个操作符和它的操作数,一个字面值,一个变量名等等)都代表着两个独立属性:类型+属性分类。在现代C++中

 glvalue(泛左值)                 = lvalue (传统意义上的左值)+ xvalue(消亡值,通过右值引用产生)
rvalue (传统意义上的右值) = prvalue(纯右值) + xvalue

Primary categories


1. lvalue(左值)

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; 
    (前自增是左值,可以取地址,即&++a)
  • *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); 
    (内建下标运算符,(在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; (内建.运算符,a是左值,当m是非静态成员函数或者数据时,表达式为左值)
  • p->m, the built-in member of pointer expression, except where m is a member enumerator or a non-static member function; (内建->运算符,除了m是枚举或者非静态成员函数,否则都是左值)
  • 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!"; 
    (特别注意,C++规定字符串是左值)
  • 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; 
    (C++ 11 类里面的指定左值返回类型的成员函数(即 class{ void fun()&; },fun是左值))
  • a cast expression to rvalue reference to function type, such as static_cast<void (&&)(int)>(x). 
    (C++ 11 右值强转函数类型)

Properties:

  • Same as glvalue (below).
  • Address of an lvalue may be taken: &++i[1] 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.

总结:

简单的来说,能取地址的变量一定是左值,有名字的变量也一定是左值,最经典的void fun(p&& shit),其中shit也是左值,因为右值引用是左值(所以才会有move,forward这些函数的产生,其中move出来一定是右值,forward保持变量形式和之前的不变,就是为了解决右值引用是左值的问题)。

至于为什么不能把等号左边看成左值,因为在C++中,等号是可以运算符重载的,等号完全可以重载成为等号左边为右值的形式。

2. prvalue(纯右值)

The following expressions are prvalue expressions:

  • a literal (except for string literal), such as 42, true or nullptr; 
    (字面值常量,除了字符串,都是纯右值,包括空指针,true和false)
  • 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[2], or where a is an rvalue and m is a non-static data member of non-reference type (until C++11); (内建.运算符,m可以是枚举或者成员函数,在C++11还可以是纯右值)
  • p->m, the built-in member of pointer expression, where m is a member enumerator or a non-static member function[2]; (内建->运算符,m可以是枚举或者成员函数)
  • a.*mp, the pointer to member of object expression, where mp is a pointer to member function[2], or where a is an rvalue and mp is a pointer to data member (until C++11); 
    (内建.*运算符m可以是枚举或者成员函数,在C++11还可以是纯右值)
  • p->*mp, the built-in pointer to member of pointer expression, where mp is a pointer to member function[2]; 
    (内建->*运算符,m可以是枚举或者成员函数)
  • 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(x), std::string{}, or (int)42;
  • the this pointer; 
    (this指针也是纯右值,因为this也是一个地址)
  • a lambda expression, such as [](int x){ return x * x; }.(since C++11) 
    (lambda表达式是纯右值)

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 non-array prvalue cannot be cv-qualified. 
    (不是class也不是数组的纯右值不能声明为const, volatile, const-volatile)
  • A prvalue cannot have incomplete type (except for type void, see below, or when used in decltype specifier). 
    (纯右值不能是不完整类型)

  

总结:

纯右值是传统右值的一部分,纯右值是表达式产生的中间值,不能取地址。

3. xvalue(消亡值)

The following expressions are xvalue expressions:

  • a function call or an overloaded operator expression of rvalue reference to object return type, such as std::move(x); 
    (注意:返回右值引用的表达式(方法和运算符重载),是消亡值,而不是纯右值)
  • a[n], the built-in subscript expression, where one operand 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).
  • In particular, like all rvalues, xvalues bind to rvalue references, and like all glvalues, xvalues may be polymorphic, and non-class xvalues may be cv-qualified. 
    (消亡连接右值表达式,可以是动态类型,但是非class的类型不能是cv-qualified的)

总结:

本质上,消亡值就是通过右值引用产生的值。右值一定会在表达式结束后被销毁,比如return x(x被copy以后会被销毁), 1+2(3这个中间值会被销毁)。

Mixed categories


1. glvalue(泛左值)

A glvalue expression is either lvalue or xvalue.

Properties:

  • A glvalue may be implicitly converted to a prvalue with lvalue-to-rvalue, array-to-pointer, or function-to-pointer implicit 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.

2. rvalue(右值)

An rvalue expression is either prvalue or xvalue.

Properties:

  • Address of an rvalue may not be taken: &int(), &i++[3], &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.(since C++11)
  • 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) 
    (在C++11中,如果存在一个函数的两个重载(只有某个参数不同,且这个参数在一个重载中是右值引用,另一个是const左值引用),此时用右值调用这个重载函数,将会匹配右值引用的函数)

Special categories


Pending member function call

  • The expressions a.mf and p->mf, where mf is a non-static member function, and the expressions a.mfp and p->mfp, where mfp is a pointer to member function, are classified as prvalue expressions, but they cannot be used to initialize references, as function arguments, or for any purpose at all, except as the left-hand argument of the function call operator, e.g. (p->*mfp)(args).

Void expressions

  • Function call expressions returning void, cast expressions to void, and throw-expressions are classified as prvalue expressions, but they cannot be used to initialize references or as function arguments. They can be used in discarded-value contexts (e.g. on a line of its own, as the left-hand operand of the comma operator, etc.) and in the return statement in a function returning void. In addition, throw-expressions may be used as the second and the third operands of the conditional operator ?:. Void expressions have no result object (since C++17)

Bit fields

  • An expression that designates a bit field (e.g. a.m, where a is an lvalue of type struct A { int m: 3; }) is an lvalue expression: it may be used as the left-hand operand of the assignment operator, but its address cannot be taken and a non-const lvalue reference cannot be bound to it. A const lvalue reference can be initialized from a bit-field lvalue, but a temporary copy of the bit-field will be made: it won't bind to the bit field directly.

(位域是左值,但是位域不能取地址,也不能将一个非const引用绑定到位域上,但是const引用可以绑定到一个位域上,但此时会产生一个临时变量)

Footnotes

  1. Assuming i has built-in type or the pre-increment operator is overloaded to return by lvalue reference

    2 2.0 2.1 2.2 2.3 special rvalue category, see pending member function call

  2. Assuming i has built-in type or the postincrement operator is not overloaded to return by lvalue reference

  3. "A difference of opinion within the C community centered around the meaning of lvalue, one group considering an lvalue to be any kind of object locator, another group holding that an lvalue is meaningful on the left side of an assigning operator. The C89 Committee adopted the definition of lvalue as an object locator" -- ANSI C Rationale, 6.3.2.1/10

  4. "New" Value Terminology by Bjarne Stroustrup, 2010

  5. const prvalues (only allowed for class types) and const xvalues do not bind to T&& overloads, but they bind to the const T&& overloads, which are also classified as "move constructor" and "move assignment operator" by the standard, satisfying the definition of "can be moved from" for the purpose of this classification. However, such overloads cannot modify their arguments and are not used in practice; in their absence const prvalues and const xvalues bind to const T& overloads.

  翻译自:http://en.cppreference.com/w/cpp/language/value_category#cite_ref-1有删改

C++ lvalue,prvalue,xvalue,glvalue和rvalue详解(from cppreference)的更多相关文章

  1. C++11 左值、右值、右值引用详解

    C++11 左值.右值.右值引用详解 左值.右值 在C++11中所有的值必属于左值.右值两者之一,右值又可以细分为纯右值.将亡值. 在C++11中可以取地址的.有名字的就是左值,反之,不能取地址的.没 ...

  2. keil MDK编译器警告和错误详解(不定期更新)

    工作后从单片机转成ARM,刚开始用ADS1.2编译器,用了一段时间,因为我接手的项目的老程序正是用ADS编译的,部门也大都在用.在学单片机的时候用的是keil c51编译器,ads和这个编译器在易用性 ...

  3. C++引用(&)详解

    C++引用详解 引用的概念 引用:就是某一变量(目标)的一个别名,对引用的操作与对变量直接操作完全一样. 引用的声明方法:类型标识符 &引用名=目标变量名: 如下:定义引用ra,它是变量a的引 ...

  4. 孙鑫视频VC++深入详解学习笔记

    孙鑫视频VC++深入详解学习笔记 VC++深入详解学习笔记 Lesson1: Windows程序运行原理及程序编写流程 Lesson2: 掌握C++基本语法 Lesson3: MFC框架程序剖析 Le ...

  5. php课程 1-3 web项目中php、html、js代码的执行顺序是怎样的(详解)

    php课程 1-3 web项目中php.html.js代码的执行顺序是怎样的(详解) 一.总结 一句话总结:b/s结构 总是先执行服务器端的先.js是客户端脚本 ,是最后执行的.所以肯定是php先执行 ...

  6. JDK19新特性使用详解

    前提 JDK19于2022-09-20发布GA版本,本文将会详细介绍JDK19新特性的使用. 新特性列表 新特性列表如下: JPE-405:Record模式(预览功能) JPE-422:JDK移植到L ...

  7. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

  8. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  9. EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

随机推荐

  1. Unity3D脚本:更改脚本和类名,且不破坏现有脚本引用的方法

    Unity开发过程中,难免遇到需要修改类名(以及对应脚本名)的时候,但如果草率地在MonoDevelop里把类名直接改掉,会破坏现有场景以 及Project Assets中所有引用该脚本的链接,届时还 ...

  2. C# 面向对象之继承

    Object是所有类的基类 1.在C#中一个类可以继承另一个类(密封类除外,静态类是密封的不能被继承); 2.被继承的类被成为基类(父类);继承的类被成为派生类(子类); 3.子类将获得父类除构造函数 ...

  3. NOIP前计划

    距离NOIp还有13天 距离继续学/退役还有13天 是时候列一波计划了 1. 要学的东西 cdq分治(突然发现cdq分治不太行,而且说不定可以用来代替想不出来的数据结构题) 主席树(写的太少啦,不熟练 ...

  4. UVA10129:Play on Words(欧拉回路)

    Some of the secret doors contain a very interesting word puzzle. The team of archaeologists has to s ...

  5. Hadoop工作流引擎之Azkaban与Oozie对比(四)

    Azkaban是什么?(一) Azkaban的功能特点(二) Azkaban的架构(三) 不多说,直接上干货! http://www.cnblogs.com/zlslch/category/93883 ...

  6. 完成FileUpload的文件上传功能,且可改按钮样式

    FileUpload控件: 更改按钮样式思路: 自己定义一个按钮,设置该按钮的样式,然后将FileUpload控件通过定位定在自己定义的按钮上面,设置z-index,使得控件浮在自己定义的按钮上面,记 ...

  7. 開玩樹莓派(一):安裝Raspbian系統

    目錄: 開玩樹莓派(一):安裝Raspbian系統 開玩樹莓派(二):配置IP,實現無顯示器局域網內Putty連接和RDP遠程 開玩樹莓派(三):Python編程 開玩樹莓派(四):GPIO控制和遠程 ...

  8. Vue的十个常用指令

    1.v-text:用于更新标签包含的文本,作用和{{}}的效果一样. 2.v-html:绑定一些包含html代码的数据在视图上. 3.v-show:用来控制元素的display属性,和显示隐藏有关.v ...

  9. WebService学习之旅(四)Apache Axis2的安装

    一.Axis2简介 Axis2是目前使用较多的WebService引擎,它是Axis1.x的升级版本,不仅支持SOAP1.1和SOAP1.2,而且也提供了对REST风格WebService的支持. A ...

  10. IOS中Llabel整理

    ·UILable是iPhone界面最基本的控件,主要用来显示文本信息.·常用属性和方法有:1.创建CGRect rect = CGRectMake(100, 200, 50, 50);UILabel ...