首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类、Rvalue和Rvalue引用

类、Rvalue和Rvalue引用
EN

Stack Overflow用户
提问于 2011-03-10 22:41:09
回答 1查看 3.2K关注 0票数 14

lvalue是一个绑定到一定内存区域的值,rvalue是一个表达式值,它的存在是暂时的,并且不一定是指确定的记忆区域。每当在期望rvalue的位置使用lvalue时,编译器将执行lvalue到rvalue的转换,然后继续进行计算。

http://www.eetimes.com/discussion/programming-pointers/4023341/Lvalues-and-Rvalues

每当我们构造一个临时(匿名)类对象或从函数返回一个临时类对象时,尽管该对象是临时的,但它是可寻址的。但是,对象仍然是一个有效的rvalue。这意味着当编译器期望使用lvalue时,对象是a)可寻址的rvalue或b)被隐式地从lvalue转换为rvalue。

例如:

代码语言:javascript
复制
class A
{
public:
    int x;
    A(int a) { x = a; std::cout << "int conversion ctor\n"; }
    A(A&) { std::cout << "lvalue copy ctor\n"; }
    A(A&&) { std::cout << "rvalue copy ctor\n"; }
};
A ret_a(A a) 
{
    return a;
}

int main(void)
{
    &A(5); // A(5) is an addressable object
    A&& rvalue = A(5); // A(5) is also an rvalue
}

我们还知道,由函数返回的临时对象返回(在下面的情况下是a)是lvalue,因为这个代码段:

代码语言:javascript
复制
int main(void)
{
    ret_a(A(5));
}

产生以下输出:

int conversion ctor

lvalue copy ctor

指示使用实际参数ret_a调用函数A(5)调用转换构造函数A::A(int),该构造函数用值5构造函数的形式参数a

当函数完成执行时,它使用a作为参数构造一个临时a对象,该参数调用A::A(A&)。但是,如果要从重载构造函数列表中删除A::A(A&),则返回的临时对象仍将与rvalue-引用构造函数A::A(A&&)匹配。

这就是我不太理解的:对象a如何匹配rvalue引用和lvalue引用?显然,A::A(A&)A::A(A&&)更匹配(因此a必须是一个lvalue)。但是,由于rvalue引用不能初始化为lvalue,因此,考虑到形式参数a是lvalue,它不应该能够匹配对A::A(A&&)的调用。如果编译器正在进行从lvalue到rvalue的转换,这将是微不足道的。从'A‘到'A&’的转换也很简单,这两个函数都应该有相同的隐式转换序列,因此,当A::A(A&)A::A(A&&)都在重载的函数候选集中时,编译器不应该能够推断出最佳匹配函数。

此外,我以前提出的问题是:

给定的对象如何匹配rvalue引用和lvalue引用?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2011-03-11 00:36:32

对我来说:

代码语言:javascript
复制
int main(void)
{
    ret_a(A(5));
}

产量:

代码语言:javascript
复制
int conversion ctor
rvalue copy ctor

(即rvalue,而不是lvalue)。这是编译器中的一个bug。然而,这是可以理解的,因为仅仅几个月前(2010年11月),针对这种行为的规则发生了变化。下面会有更多的介绍。

当函数完成执行时,它使用a作为参数构造一个临时a对象,该参数调用A::A(A&)

其实没有。当函数ret_a完成执行时,它使用a作为参数构造一个临时A对象,该参数调用A:A(A&&)。这要归功于class.copy/p33]1

如果符合或将满足复制操作的省略条件,除非源对象是函数参数,并且要复制的对象由lvalue指定,则首先执行重载解析,以选择副本的构造函数,就好像对象是由rvalue指定的一样。如果重载解析失败,或者所选构造函数的第一个参数的类型不是对象类型的rvalue引用(可能是cv限定的),则再次执行重载解析,将对象视为lvalue。注意:无论复制是否会发生,这种两阶段过载解决方案都必须执行.如果不执行省略,它将确定要调用的构造函数,即使调用被省略,所选的构造函数也必须是可访问的。-尾注

但是,如果删除A::A(A&&)构造函数,则将选择A::A(&)作为返回。尽管在这种情况下,参数a的构造将失败,因为您不能使用rvalue来构造它。然而,暂时忽略这一点,我相信你的最终问题是:

给定的对象如何匹配rvalue引用和lvalue引用?

在提及该声明时:

代码语言:javascript
复制
return a;

答案是在上面引用的标准草案段落中:第一次过载解析被尝试,就好像a是一个rvalue一样。如果失败,将使用a作为lvalue再次尝试重载解析。这个两阶段的过程只在允许复制省略的上下文中尝试(例如返回语句)。

最近对C++0x草案进行了更改,以便在返回通过值传递的参数时允许两阶段过载解析过程(如您的示例中所示)。这就是我们所看到的不同编译器的不同行为的原因。

票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5266783

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档