类、右值和右值引用
左值是绑定到确定的内存区域的值,而右值是其存在是临时的并且不一定引用确定的内存区域的表达式值。每当在需要右值的位置使用左值时,编译器都会执行左值到右值的转换,然后继续进行计算。
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
表示使用实参A(5)
调用函数ret_a
调用转换构造函数A::A(int)
构造函数的形式参数 a
,其值为 5。
当函数完成执行时,它会构造一个临时 A
使用 a
作为参数的对象,它调用 A::A(A&)
。但是,如果我们从重载构造函数列表中删除 A::A(A&)
,则返回的临时对象仍将与右值引用构造函数 A::A(A& ;&)
。
这是我不太明白的地方:对象 a
如何同时匹配右值引用和左值引用?很明显,A::A(A&)
比 A::A(A&&)
更好匹配(因此 a
code> 必须是左值)。但是,由于右值引用无法初始化为左值,且形式参数 a
是左值,因此它不应该能够匹配对 A::A(A& &)
。如果编译器正在进行左值到右值的转换,那么这将是微不足道的。事实上,从“A”到“A&”的转换也是微不足道的,两个函数应该具有相同的隐式转换序列等级,因此,当 A::A(A&)
和 都存在时,编译器不应该能够推断出最佳匹配函数A::A(A&&)
位于重载函数候选集中。
此外,问题(我之前问过)是:
给定的对象如何匹配右值引用和左值引用?
An lvalue is a value bound to a definitive region of memory whereas an rvalue is an expression value whose existence is temporary and who does not necessarily refer to a definitive region of memory. Whenever an lvalue is used in a position in which an rvalue is expected, the compiler performs an lvalue-to-rvalue conversion and then proceeds with evaluation.
http://www.eetimes.com/discussion/programming-pointers/4023341/Lvalues-and-Rvalues
Whenever we construct a temporary (anonymous) class object or return a temporary class object from a function, although the object is temporary, it is addressable. However, the object still is a valid rvalue. This means that the object is a) an addressable rvalue or b) is being implicitly converted from an lvalue to an rvalue when the compiler expects an lvalue to be used.
For instance:
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
}
We also know that temporary objects returned (in the following case a
) by functions are lvalues as this code segment:
int main(void)
{
ret_a(A(5));
}
yields the following output:
int conversion ctor
lvalue copy ctor
Indicating that the call to the function ret_a
using actual argument A(5)
calls the conversion constructor A::A(int)
which constructs the function's formal argument a
with the value 5.
When the function completes execution, it then constructs a temporary A
object using a
as its argument, which invokes A::A(A&)
. However, if we were to remove A::A(A&)
from the list of overloaded constructors, the returned temporary object would still match the rvalue-reference constructor A::A(A&&)
.
This is what I'm not quite understanding: how can the object a
match both an rvalue reference and an lvalue reference? It is clear that A::A(A&)
is a better match than A::A(A&&)
(and therefore a
must be an lvalue). But, because an rvalue reference cannot be initialized to an lvalue, given that the formal argument a
is an lvalue, it should not be able to match the call to A::A(A&&)
. If the compiler is making an lvalue-to-rvalue conversion it would be trivial. The fact that a conversion from 'A' to 'A&' is also trivial, both functions should have identical implicit conversion sequence ranks and therefore, the compiler should not be able to deduce the best-matching function when both A::A(A&)
and A::A(A&&)
are in the overloaded function candidate set.
Moreover, the question (which I previously asked) is:
How can a given object match both an rvalue reference and an lvalue reference?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
对我来说:
产量:(
即右值,而不是左值)。这是您的编译器中的错误。不过,这是可以理解的,因为这种行为的规则仅在几个月前(2010 年 11 月)发生了变化。下面详细介绍这一点。
其实没有。当函数
ret_a
完成执行时,它会使用a
作为参数构造一个临时A
对象,该对象调用A:A( A&&)
。这是由于 [class.copy]/p33]1:但是,如果删除
A::A(A&&)
构造函数,则将选择A::A(&)
作为返回值。尽管在这种情况下,参数a
的构造将会失败,因为您无法使用右值构造它。然而暂时忽略这一点,我相信你的最终问题是:引用声明:
答案在上面引用的标准草案段落中:首先尝试重载解析,就好像
a
是右值一样。如果失败,则会使用a
作为左值再次尝试重载解析。仅在允许复制省略的上下文(例如 return 语句)中尝试此两阶段过程。C++0x 草案最近刚刚进行了更改,以允许在返回按值传递的参数时进行两阶段重载解析过程(如您的示例中所示)。这就是我们所看到的不同编译器行为不同的原因。
For me:
Yields:
(i.e. rvalue, not lvalue). This is a bug in your compiler. However it is understandable as the rules for this behavior changed only a few months ago (Nov. 2010). More on this below.
Actually no. When the function
ret_a
completes execution, it then constructs a temporaryA
object usinga
as its argument, which invokesA:A(A&&)
. This is due to [class.copy]/p33]1:However if you remove the
A::A(A&&)
constructor, thenA::A(&)
will be chosen for the return. Although in this case, then the construction of the argumenta
will fail because you can't construct it using an rvalue. However ignoring that for the moment, I believe your ultimate question is:in referring to the statement:
And the answer is in the above quoted paragraph from the draft standard: First overload resolution is tried as if
a
is an rvalue. And if that fails, overload resolution is tried again usinga
as an lvalue. This two-stage process is tried only in the context wherein copy elision is permissible (such as a return statement).The C++0x draft has just recently been changed to allow the two-stage overload resolution process when returning arguments that have been passed by value (as in your example). And that is the reason for the varying behavior from different compilers that we are seeing.