类,Rvalues和Rvalue引用

时间:2011-03-10 22:41:10

标签: c++ reference rvalue-reference rvalue lvalue

左值是绑定到存储器的确定区域的值,而右值是表达式值,其存在是临时的,并且不一定是指存储器的确定区域。只要在预期rvalue的位置使用左值,编译器就会执行左值到右值的转换,然后继续进行评估。

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

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

例如:

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)是左值作为此代码段:

int main(void)
{
    ret_a(A(5));
}

产生以下输出:

int conversion ctor

lvalue copy ctor

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

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

这就是我不太了解的内容:对象a如何匹配右值引用和左值引用?很明显A::A(A&)A::A(A&&)更匹配(因此a必须是左值)。但是,因为rvalue引用不能初始化为左值,假定形式参数a是左值,它应该不能匹配对A::A(A&&)的调用。如果编译器正在进行左值到右值的转换,那将是微不足道的。从'A'转换为'A&amp;'的事实也是微不足道的,两个函数都应该具有相同的隐式转换序列,因此,当A::A(A&)A::A(A&&)都在重载函数候选集中时,编译器不应该推导出最佳匹配函数。

此外,问题(我之前提出的问题)是:

给定对象如何匹配右值引用和左值引用?

1 个答案:

答案 0 :(得分:6)

对我来说:

int main(void)
{
    ret_a(A(5));
}

收率:

int conversion ctor
rvalue copy ctor

(即rvalue,而不是左值)。这是编译器中的错误。然而,这是可以理解的,因为这种行为的规则仅在几个月前(2010年11月)发生了变化。更多内容如下。

  

当函数完成执行时,   然后构建一个临时的A   使用a作为参数的对象   调用A::A(A&)

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

  

当elision的标准   复制操作已满足或将被满足   除了源的事实   object是一个函数参数,和   指定要复制的对象   通过左值,重载决议来   选择副本的构造函数是   首先表现就像对象一样   由右值指定。如果过载   分辨率失败,或者类型如何   所选的第一个参数   构造函数不是右值引用   到对象的类型(可能   cv-qualified),重载分辨率是   再考虑一下   对象作为左值。 [注意:这个   必须进行两级重载分辨率   无论是否复制都执行   将会出现这种情况。它决定了   如果省略则调用构造函数   未执行,并且已选中   即使构造函数必须是可访问的   电话被忽略了。 - 结束说明]

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

  

给定对象如何匹配两者   右值参考和左值   参考

参考声明:

return a;

答案在标准草案的上述段落中:首先尝试重载解析,好像a是一个右值。如果失败,则使用a作为左值再次尝试重载决策。只有在允许复制省略的情况下(例如返回陈述)才会尝试这两个阶段的过程。

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