什么表达式创建x值
What expressions create xvalues?
我正在努力理解C++11的概念。
我说的标准草案:
xvalue(一个"eXpiring"值)也指的是一个物体,通常在其寿命即将结束时(因此资源可以被移动)。xvalue是某些类型的表达式的结果,包括右值引用(8.3.2)。[示例:调用返回类型为右值的函数的结果引用是一个x值--结束示例]
那么,产生x值的"特定类型的表达式"到底是什么呢?规范的这一部分没有详细列出这些表达式的列表。
我理解lvalue和prvalue(至少我认为,我理解)。
在§5(C++11§5[expr]/6)的引言中有一个有用的非规范性注释:
[注意:如果表达式是:,则它是一个xvalue
调用函数(无论是隐式还是显式)的结果,该函数的返回类型是对对象类型的右值引用
转换为对对象类型的右值引用
指定非引用类型的非静态数据成员的类成员访问表达式,其中对象表达式是x值或
指向成员表达式的CCD_ 1指针,其中第一操作数是x值,第二操作数是指向数据成员的指针。
一般来说,这个规则的效果是命名的右值引用被视为左值,而对对象的未命名右值引用则被视为x值;对函数的右值引用被视为左值,无论是否命名--尾注]
搜索§5的其余部分,该列表似乎是详尽无遗的。列表后面是一个示例:
struct A { int m; }; A&& operator+(A, A); A&& f(); A a; A&& ar = static_cast<A&&>(a);
表达式
f()
、f().m
、static_cast<A&&>(a)
和a + a
是x值。表达式ar
是一个左值。
有两种常见的方法可以获得xvalue表达式:
-
使用
std::move
移动对象。CCD_ 8对右值引用类型执行CCD_ 9并返回右值引用。 -
使用
.*
0转发右值。CCD_ 11通常用于函数模板中,以实现函数自变量的完美转发。如果提供给函数模板的参数是右值,则参数类型将是右值引用,即左值。在这种情况下,
std::forward
对右值引用类型执行static_cast
,并返回右值引用。(注意:如果提供给函数模板的参数是左值,则参数类型将是左值引用,
std::forward
将返回左值引用。)
描述有效表达式语法的第5条为每个表达式语法列出了表达式为lvalue、xvalue或prvalue的条件。第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_cast<Type>(expr)
:5.2.7第2段static_cast<Type>(expr)
:5.2.9第1段reinterpret_cast<Type>(expr)
:5.210第1段const_cast<Type>(expr)
:5.211第1段(Type) expr
:5.4第1段
表达式是x值,当且仅当CCD_ 29是对对象类型的右值引用。Type(expr)
也是如此,因为
5.2.3第1段:如果表达式列表[在类型名称后面的括号中]是单个表达式,则类型转换表达式等效于相应的强制转换表达式(5.4)
(另一方面,Type{expr}
总是一个prvalue。)
关于条件运算符的第5.16节最后指出,如果B和/或C是x值,则A ? B : C
有时可以是x值。但完整的规则很难概括。
如果一个表达式最终调用了用户定义的重载运算符函数,则第5.2.2节适用于该表达式,而不是描述内置运算符行为的表达式。(请参阅@James发布的示例中的表达式a + a
。)
如您所述,
xvalue("eXpiring"值)也指对象,通常在其生命周期即将结束时(例如,这样它的资源就可以移动)。
焦点:object
、be moved
、end lifetime
这里有一个例子:
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;
}
通过移动,我们可以将命名值(左值,这里是s
)转换为右值(即std::move(s)
)。更具体地说,因为它不可能是prvalue
(它有一个名称!换句话说,它有一种身份),所以它最终会成为xvalue
。
xvalue
始终服务于C++移动语义。
xvalue只是一个存储可能已被释放的右值,因此使用它意味着您必须自己验证它的存在。
一般来说,它是一个或多个级别的间接远离一个实际的右值。
相比之下,只要在作用域中,就保证右值的存储空间是存在的。
我可能错了,但这是我所理解的。
- 使用成员在类中创建 lambda 表达式
- 在函数中使用 const int size 参数创建数组会在 Visual Studio 中抛出错误 C++:表达式的计
- 创建结构体向量,表达式:向量下标超出范围
- 使用 lambda 表达式创建线程时,如何为每个线程提供自己的 lambda 表达式副本
- 使用makeword函数创建错误e0109-表观呼叫的括号前表达式必须具有(指针到 - )函数类型
- 使用参数包和元组创建一个简单的表达式类
- 如何创建适用于 lambda 表达式的排序函数
- 从折叠表达式创建带有分度的字符串
- 异常表达式创建的异常对象的类型
- "std::string + char"表达式会创建另一个 std::string 吗?
- 是否可以创建一个字符串数组,如果是的话,为什么我会遇到此错误:错误:预期表达式
- #include < regex.h> 用于创建正确正则表达式的问题
- 在不使用lambda的情况下,我如何整齐地创建一个表达式的函数
- 什么表达式创建x值
- 使用自动关键字创建的类型的表达式模板中存在分段错误
- 从嵌套循环创建数学表达式
- 如何从嵌套的 lambda 表达式函子类创建
- 如何从队列中的运算符和操作数创建数学表达式
- 创建单个正则表达式而不是多个正则表达式
- 使用数字和字符操作符创建表达式