C++ 类、右值和右值引用
左值是一个绑定到内存的确定区域的值,而右值是一个表达式值,它的存在是暂时的,不一定指内存的确定区域。每当在预期右值的位置使用左值时,编译器将执行左值到右值的转换,然后继续求值 无论何时构造临时(匿名)类对象或从函数返回临时类对象,尽管该对象是临时的,但它是可寻址的。但是,该对象仍然是有效的右值。这意味着对象是a)一个可寻址的右值,或者b)当编译器期望使用左值时,正在从左值隐式转换为右值 例如:C++ 类、右值和右值引用,c++,reference,rvalue-reference,rvalue,lvalue,C++,Reference,Rvalue Reference,Rvalue,Lvalue,左值是一个绑定到内存的确定区域的值,而右值是一个表达式值,它的存在是暂时的,不一定指内存的确定区域。每当在预期右值的位置使用左值时,编译器将执行左值到右值的转换,然后继续求值 无论何时构造临时(匿名)类对象或从函数返回临时类对象,尽管该对象是临时的,但它是可寻址的。但是,该对象仍然是有效的右值。这意味着对象是a)一个可寻址的右值,或者b)当编译器期望使用左值时,正在从左值隐式转换为右值 例如: class A { public: int x; A(int a) { x = a;
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
}
产生以下输出:
int转换系数
左值复制ctor
指示使用实际参数a(5)
调用函数ret_a
调用转换构造函数a::a(int)
,该构造函数使用值5构造函数的形式参数a
当函数完成执行时,它使用a
作为参数构造一个临时a
对象,该对象调用a::a(a&)
。但是,如果我们要从重载构造函数列表中删除A::A(A&)
,则返回的临时对象仍将匹配右值引用构造函数A::A(A&&)
这是我不太理解的:对象a
如何同时匹配右值引用和左值引用?很明显,A::A(A&)
比A::A(A&&)
更匹配(因此A
必须是左值)。但是,由于右值引用不能初始化为左值,因此如果形式参数a
是左值,则它不应该能够匹配对a::a(a&&)
的调用。如果编译器正在进行从左值到右值的转换,这将是微不足道的。从“a”到“a&”的转换也很简单,这两个函数应该具有相同的隐式转换序列秩,因此,当a::a(a&)
和a::a(a&&)
都在重载函数候选集中时,编译器不应该能够推断出最佳匹配函数
此外,我先前提出的问题是:
给定对象如何同时匹配右值引用和左值引用?对于我来说:
int main(void)
{
ret_a(A(5));
}
收益率:
int conversion ctor
rvalue copy ctor
(即右值,而非左值)。这是编译器中的一个错误。然而,这是可以理解的,因为这种行为的规则仅在几个月前(2010年11月)发生了变化。下面将对此进行详细介绍
当函数完成执行时,
然后它构造一个临时a
使用a
作为其参数的
调用A::A(A&)
实际上不是。当函数ret_a
完成执行时,它使用a
作为参数构造一个临时a
对象,该对象调用a:a(a&&)
。这是由于[class.copy]/p33]:
当删除一个
满足或将满足复制操作
除了源代码
对象是函数参数,并且
要复制的对象已指定
通过左值,重载解析为
选择要创建的副本的构造函数
首先执行,就好像对象是
由右值指定。如果过载
解析失败,或者
选定对象的第一个参数
构造函数不是右值引用
到对象的类型(可能是
cv合格),过载分辨率为
再次执行,考虑到
对象作为左值。[注:此
必须使用两级过载解决方案
无论是否复制,都将执行
将发生省略。它决定了
如果省略为,则调用构造函数
未执行,并且已选择
构造函数必须是可访问的,即使
电话被省略了。-结束语]
但是,如果删除A::A(A&&)
构造函数,则返回将选择A::A(&)
。尽管在这种情况下,参数a
的构造将失败,因为不能使用右值构造它。然而,暂时忽略这一点,我相信你的最终问题是:
一个给定的对象如何与两个对象匹配
右值引用和左值
推荐人
在提及该声明时:
return a;
答案在标准草案的上面引用的段落中:第一个重载解析被尝试,就好像a
是一个右值一样。如果失败,将使用a
作为左值再次尝试重载解析。此两阶段过程仅在允许复制省略的上下文中(例如返回语句)进行尝试
C++0x草案最近刚刚被修改,以允许在返回按值传递的参数时执行两阶段重载解析过程(如您的示例所示)。这就是我们所看到的不同编译器的不同行为的原因。“左值”和“右值”指的是表达式,而不是对象。谢谢。我猜接下来的问题是a对象如何同时绑定到右值和左值引用?另外:“int n=3;n是一个引用int对象的表达式。表达式n是一个左值。”如果这是正确的,那么
a
对象(上面)在初始化时不会被认为是一个表达式吗?@Howard感谢大家的理解。但是没有,在我最初的问题中没有o型。调用了A::A(A&)
。您使用的是哪种编译器?我使用的是MSVC++除了源对象是一个函数参数这一事实之外,还有什么是“或者将要满足的”意思?@没有人:看起来[class.copy]/p33只是还没有在编译器中实现。这一部分我有点惊讶
return a;