C++ 什么表达式创建XValue?

C++ 什么表达式创建XValue?,c++,c++11,language-lawyer,xvalue,C++,C++11,Language Lawyer,Xvalue,我试图理解C++11的概念 我的标准草案说: xvalue(一个“到期”值)也指一个对象,通常在其生命周期结束时(因此 例如,可以移动资源)。xvalue是某些类型表达式的结果,这些表达式涉及 右值参考(8.3.2)。[示例:调用返回类型为右值的函数的结果 引用是一个xvalue。-结束示例] 好的,那么产生xvalue的“特定类型的表达式”到底是什么呢?规范的这一部分没有详细说明这些表达式的列表 我理解左值和prvalue(至少我认为我理解)。在§5(C++11§5[expr]/6)的介绍中有

我试图理解C++11的概念

我的标准草案说:

xvalue(一个“到期”值)也指一个对象,通常在其生命周期结束时(因此 例如,可以移动资源)。xvalue是某些类型表达式的结果,这些表达式涉及 右值参考(8.3.2)。[示例:调用返回类型为右值的函数的结果 引用是一个xvalue。-结束示例]

好的,那么产生xvalue的“特定类型的表达式”到底是什么呢?规范的这一部分没有详细说明这些表达式的列表


我理解左值和prvalue(至少我认为我理解)。

在§5(C++11§5[expr]/6)的介绍中有一个有用的非规范性注释:

[注意:如果表达式是:

  • 隐式或显式调用其返回类型为对对象类型的右值引用的函数的结果

  • 对对象类型的右值引用的强制转换

  • 类成员访问表达式,指定非引用类型的非静态数据成员,其中对象表达式是xvalue,或

  • 指向成员表达式的
    *
    指针,其中第一个操作数是xvalue,第二个操作数是指向数据成员的指针

一般来说,此规则的效果是,命名的右值引用被视为左值,而对对象的未命名右值引用被视为XValue;对函数的右值引用被视为左值,无论是否命名。-结束注释]

通过搜索§5的其余部分,该列表似乎详尽无遗。列表后面是一个示例:

void move_test(){
    std::string s = "I'm here!";
    std::string m  =  std::move(s);  // move from <s> to <m>
    // s is now in an undefined, but valid state; 
    std::cout << "s=" << s << "; &s=" << &s << std::endl;
}
结构A{ int m; }; A&&运算符+(A,A); A&&f(); A A; A&&ar=静态(A); 表达式
f()
f().m
static\u cast(a)
a+a
都是x值。表达式
ar
是左值

获取xvalue表达式有两种常见方法:

  • 使用
    std::move
    移动对象<代码>标准::移动对右值引用类型执行
    静态转换
    ,并返回右值引用

  • 使用
    std::forward
    转发右值
    std::forward
    通常用于函数模板中,以实现函数参数的完美转发

    如果提供给函数模板的参数是右值,则参数类型将是右值引用,这是一个左值。在这种情况下,
    std::forward
    对右值引用类型执行
    static\u cast
    ,并返回右值引用

    (注意:如果提供给函数模板的参数是左值,则参数类型将是左值引用,
    std::forward
    将返回左值引用。)


第5条描述了有效表达式的语法,为每个表达式语法列出了表达式为左值、X值或PR值的条件。第5条中可能的X值的完整列表如下:

5.2.2第10段:函数调用是。。。如果结果类型是对对象类型的右值引用,则为xvalue

(在标准的技术语言中,“对象类型”与“类类型”的含义不同。“对象类型”包括基本类型、指针和数组,仅排除函数类型。函数类型的右值引用始终被视为左值,而不是xvalue。)

返回右值引用的最显著的函数当然是
std::move
,有时是
std::forward

5.2.5第4段:如果
E2
是非静态数据成员。。。如果
E1
是一个x值,则
E1.E2
是一个x值

(另一方面,数据成员查找
E1->E2
始终是左值。)

类似地,如果
E1
是一个x值,那么数据成员查找
E1.*E2
是一个x值:

5.5第6段:
*
表达式的第二个操作数是指向数据成员的指针,其结果与其第一个操作数具有相同的值类别(3.10)

对于各种类型的强制类型转换:

  • dynamic\u cast(expr)
    :5.2.7第2段
  • static\u cast(expr)
    :5.2.9第1段
  • 重新解释铸件(expr)
    :5.2.10第1段
  • const_cast(expr)
    :5.2.11第1段
  • (类型)expr
    :5.4第1段
当且仅当
Type
是对对象类型的右值引用时,表达式才是xvalue。这同样适用于
类型(expr)
,因为

5.2.3第1段:如果表达式列表[在类型名称后面的括号中]是单个表达式,则类型转换表达式与相应的强制转换表达式(5.4)等效(定义明确,含义明确)

(另一方面,
Type{expr}
始终是一个PR值。)

关于条件运算符的第5.16节最后说
A?B:C
如果B和/或C是xvalue,则有时可以是xvalue。但完整的规则很难总结


如果表达式最终调用用户定义的重载运算符函数,则第5.2.2节适用于该表达式,而不是描述内置运算符行为的表达式。(参见@James poster示例中的表达式
a+a

我从阅读中得出的结论是,将某物称为xvalue是一种奇特的表达方式:

xvalue只是一个右值,其存储可能已被释放,因此使用它意味着您必须自己验证它的存在

通常,它是一个或多个级别的间接指向,与实际的右值不同

相反,右值的存储空间保证为l
void move_test(){
    std::string s = "I'm here!";
    std::string m  =  std::move(s);  // move from <s> to <m>
    // s is now in an undefined, but valid state; 
    std::cout << "s=" << s << "; &s=" << &s << std::endl;
}