有人可以解释rvalues,左值,POD和非POD方面的详细信息,下面标记的第一个表达式不 ok,而下面标记的第二个表达式正常吗?在我的理解中,int()和A()都应该是rvalues,不是吗?
struct A {};
int main()
{
int i;
A a;
int() = i; //Not OK (error).
A() = a; //OK.
return 0;
}
答案 0 :(得分:19)
Rvalues是你从表达式中得到的(一种有用的简化,取自C标准,但在C ++标准中没有措辞)。左值是“定位器值”。左值可以用作右值。引用总是左值,即使是const。
您必须知道的主要区别可以压缩为一个项目:您不能获取右值的地址(同样,不是标准,而是规则的有用概括)。换句话说,你不能为rvalue修复精确的位置 - 如果可以,那么你就有了一个左值。 (但是,您可以将const&绑定到右值以“将其固定到位”,并且0x正在大幅改变规则。)
然而,用户定义的类型(UDT)有点特殊:如果类的接口允许,您可以将任何右值转换为左值:
struct Special {
Special& get_lvalue() { return *this; }
};
void f() {
// remember "Special()" is an rvalue
Special* p = &Special().get_lvalue(); // even though you can't dereference the
// pointer (because the object is destroyed), you still just took the address
// of a temporary
// note that the get_lvalue() method doesn't need to operate on a const
// object (though that would be fine too, if the return type matched)
}
除了通过编译器提供的赋值运算符之外,A() = a
发生了类似的事情,将右值A()
转换为*this
。引用标准,12.8 / 10:
如果类定义未显式声明复制赋值运算符,则会声明隐式。类X的隐式声明的复制赋值运算符将具有
形式X& X::operator=(const X&)
然后它继续提供更多的资格和规格,但这是重要的一点。由于这是一个成员函数,它可以在rvalues上调用,就像Special :: get_lvalue一样,就像你写了A().operator=(a)
而不是A() = a
一样。
您发现int() = 1
被明确禁止,因为int没有以相同的方式实现operator =。但是,类型之间的这种轻微差异在实践中并不重要(至少不是我发现的)。
POD表示普通旧数据,是指定使用memcpy的要求集合等同于复制。非POD是你不能使用memcpy复制的任何类型(与POD完全相反,这里没有任何隐藏),这往往是你用C ++编写的大多数类型。作为POD或非POD不会改变上述任何一个,并且实际上是一个单独的问题。
答案 1 :(得分:2)
在我的理解中,int()和A()都应该是rvalues,不是吗?
正确,epxression T()
始终是标量和用户定义类型T
的右值。只要不涉及const
,表达式T()
就是可修改的右值,更准确一些。
涉及标量类型的赋值需要在赋值运算符的左侧有一个可修改的左值。由于int()
不是左值,因此您无法分配到int()
。
对于用户定义的类型,赋值是一个特殊的成员函数,也可以在 rvalues 上调用成员函数(参见§3.10第10节)。这就是A().operator=(a)
形成良好的原因。
答案 2 :(得分:1)
来自Does C++ do value initialization of a POD typedef?,引用标准:
表达式T(),其中T是a a的简单类型说明符(7.1.5.2) 非数组完整对象类型或 (可能是cv-qualified)void类型, 创建指定的右值 type,值初始化
因此,int()是一个右值,无法分配,如第一种情况所示。
A()不是一个simlle-type-specifyer,因此A()产生一个左值